From 5792ec43196a52eaddcfbf5a81a91bbbc8dad95e Mon Sep 17 00:00:00 2001 From: Eduardo Cavazos Date: Sun, 23 Sep 2007 13:20:28 -0500 Subject: [PATCH 01/21] boids: Use bi* in 'distance' word --- extra/boids/boids.factor | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/extra/boids/boids.factor b/extra/boids/boids.factor index 397ce6eb5a..e703472e40 100644 --- a/extra/boids/boids.factor +++ b/extra/boids/boids.factor @@ -68,7 +68,9 @@ VAR: separation-radius ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -: distance ( boid boid -- n ) boid-pos swap boid-pos v- norm ; +! : distance ( boid boid -- n ) boid-pos swap boid-pos v- norm ; + +: distance ( boid boid -- n ) [ boid-pos ] [ boid-pos ] bi* v- norm ; ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! From a66e412a35e718ecdb12b33f3d1e1672f54e4e08 Mon Sep 17 00:00:00 2001 From: Eduardo Cavazos Date: Mon, 24 Sep 2007 03:55:56 -0500 Subject: [PATCH 02/21] Use more combinators in boids --- extra/boids/boids.factor | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/extra/boids/boids.factor b/extra/boids/boids.factor index e703472e40..aa3311ada5 100644 --- a/extra/boids/boids.factor +++ b/extra/boids/boids.factor @@ -56,7 +56,7 @@ VAR: separation-radius ! random-boid and random-boids ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -: random-range ( a b -- n ) 1 + dupd swap - random + ; +: random-range ( a b -- n ) 1+ over - random + ; : random-pos ( -- pos ) world-size> [ random ] map ; @@ -68,8 +68,6 @@ VAR: separation-radius ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -! : distance ( boid boid -- n ) boid-pos swap boid-pos v- norm ; - : distance ( boid boid -- n ) [ boid-pos ] [ boid-pos ] bi* v- norm ; ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! @@ -81,7 +79,9 @@ VAR: separation-radius ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -: relative-position ( self other -- v ) boid-pos swap boid-pos v- ; +! : relative-position ( self other -- v ) boid-pos swap boid-pos v- ; + +: relative-position ( self other -- v ) swap [ boid-pos ] 2apply v- ; : relative-angle ( self other -- angle ) over boid-vel -rot relative-position angle-between ; @@ -90,7 +90,7 @@ over boid-vel -rot relative-position angle-between ; : vsum ( vector-of-vectors -- vec ) { 0 0 } [ v+ ] reduce ; -: vaverage ( seq-of-vectors -- seq ) dup vsum swap length v/n ; +: vaverage ( seq-of-vectors -- seq ) [ vsum ] [ length ] bi v/n ; : average-position ( boids -- pos ) [ boid-pos ] map vaverage ; @@ -206,14 +206,14 @@ cond ; ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -: new-pos ( boid -- pos ) dup boid-vel time-slice> v*n swap boid-pos v+ ; +: new-pos ( boid -- pos ) [ boid-pos ] [ boid-vel time-slice> v*n ] bi v+ ; : new-vel ( boid -- vel ) -dup acceleration time-slice> v*n swap boid-vel v+ normalize* ; + [ boid-vel ] [ acceleration time-slice> v*n ] bi v+ normalize* ; : wrap-pos ( pos -- pos ) { [ wrap-x ] [ wrap-y ] } parallel-call ; -: iterate-boid ( self -- self ) dup >r new-pos wrap-pos r> new-vel ; +: iterate-boid ( self -- self ) [ new-pos wrap-pos ] [ new-vel ] bi ; ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! From b9ada9413fa7a5f8050d559d93ba5189f4cb1d8f Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Mon, 24 Sep 2007 15:34:17 -0400 Subject: [PATCH 03/21] New icons from Elie --- Factor.app/Contents/Info.plist | 2 +- Factor.app/Contents/Resources/FRaptorMix.icns | Bin 53668 -> 0 bytes Factor.app/Contents/Resources/Factor.icns | Bin 0 -> 48861 bytes misc/icons/FRaptorMix.ico | Bin 92854 -> 0 bytes misc/icons/FRaptorMix_128x128.png | Bin 12101 -> 0 bytes misc/icons/FRaptorMix_16x16.png | Bin 730 -> 0 bytes misc/icons/FRaptorMix_32x32.png | Bin 1877 -> 0 bytes misc/icons/FRaptorMix_48x48.png | Bin 3481 -> 0 bytes misc/icons/Factor.ico | Bin 0 -> 92854 bytes misc/icons/Factor_128x128.png | Bin 0 -> 21526 bytes misc/icons/Factor_16x16.png | Bin 0 -> 675 bytes misc/icons/Factor_32x32.png | Bin 0 -> 1924 bytes misc/icons/Factor_48x48.png | Bin 0 -> 4326 bytes misc/icons/license.txt | 2 +- vm/factor.rs | 2 +- 15 files changed, 3 insertions(+), 3 deletions(-) delete mode 100644 Factor.app/Contents/Resources/FRaptorMix.icns create mode 100644 Factor.app/Contents/Resources/Factor.icns delete mode 100644 misc/icons/FRaptorMix.ico delete mode 100644 misc/icons/FRaptorMix_128x128.png delete mode 100644 misc/icons/FRaptorMix_16x16.png delete mode 100644 misc/icons/FRaptorMix_32x32.png delete mode 100644 misc/icons/FRaptorMix_48x48.png create mode 100644 misc/icons/Factor.ico create mode 100644 misc/icons/Factor_128x128.png create mode 100644 misc/icons/Factor_16x16.png create mode 100644 misc/icons/Factor_32x32.png create mode 100644 misc/icons/Factor_48x48.png diff --git a/Factor.app/Contents/Info.plist b/Factor.app/Contents/Info.plist index c54acd7179..ca0e6d5f8a 100644 --- a/Factor.app/Contents/Info.plist +++ b/Factor.app/Contents/Info.plist @@ -22,7 +22,7 @@ CFBundleExecutable factor CFBundleIconFile - FRaptorMix.icns + Factor.icns CFBundleIdentifier org.factorcode.Factor CFBundleInfoDictionaryVersion diff --git a/Factor.app/Contents/Resources/FRaptorMix.icns b/Factor.app/Contents/Resources/FRaptorMix.icns deleted file mode 100644 index 5cbe894480f8d39560f14983b71f08a4b57becc6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 53668 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 diff --git a/Factor.app/Contents/Resources/Factor.icns b/Factor.app/Contents/Resources/Factor.icns new file mode 100644 index 0000000000000000000000000000000000000000..ab70230e9ba80d4d48d89b476b473d45af7168fd GIT binary patch literal 48861 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
    i6PxP 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 diff --git a/misc/icons/FRaptorMix_16x16.png b/misc/icons/FRaptorMix_16x16.png deleted file mode 100644 index 1613566968f46f6281deb37656e1ac85342e3506..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 730 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 diff --git a/misc/icons/Factor.ico b/misc/icons/Factor.ico new file mode 100644 index 0000000000000000000000000000000000000000..fa4baa8cbdaf846566b6e3064cfbd21159ed27d3 GIT binary patch literal 92854 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
    cdr
    " ] +[ + [ + H{ { page-color { 1 0 1 1 } } } + [ "cdr" write ] with-nesting + ] make-html-string ] unit-test diff --git a/extra/html/html.factor b/extra/html/html.factor index 8d151906dc..9db97957a5 100644 --- a/extra/html/html.factor +++ b/extra/html/html.factor @@ -1,10 +1,43 @@ ! Copyright (C) 2004, 2006 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. -USING: generic assocs help http io io.styles io.files io.streams.string -kernel math math.parser namespaces xml.writer quotations -assocs sequences strings words html.elements ; +USING: generic assocs help http io io.styles io.files +io.streams.string kernel math math.parser namespaces +quotations assocs sequences strings words html.elements +xml.writer sbufs ; IN: html +GENERIC: browser-link-href ( presented -- href ) + +M: object browser-link-href drop f ; + +TUPLE: html-stream ; + +: ( stream -- stream ) + html-stream construct-delegate ; + + over set-delegate ; + +: ( style stream class -- stream ) + >r (html-sub-stream) r> construct-delegate ; inline + +: end-sub-stream ( substream -- string style stream ) + dup delegate >string + over html-sub-stream-style + rot html-sub-stream-stream ; + +: delegate-write ( string -- ) + stdio get delegate stream-write ; + +: object-link-tag ( style quot -- ) + presented pick at browser-link-href + [ call ] [ call ] if* ; inline + : hex-color, ( triplet -- ) 3 head-slice [ 255 * >fixnum >hex 2 CHAR: 0 pad-left % ] each ; @@ -28,166 +61,149 @@ IN: html : font-css, ( font -- ) "font-family: " % % "; " % ; -: hash-apply ( value-hash quot-hash -- ) - #! Looks up the key of each pair in the first list in the - #! second list to produce a quotation. The quotation is - #! applied to the value of the pair. If there is no - #! corresponding quotation, the value is popped off the - #! stack. - [ swapd at dup [ call ] [ 2drop ] if ] curry assoc-each ; +: apply-style ( style key quot -- style gadget ) + >r over at r> when* ; inline + +: make-css ( style quot -- str ) + "" make nip ; inline : span-css-style ( style -- str ) [ - H{ - { foreground [ fg-css, ] } - { background [ bg-css, ] } - { font [ font-css, ] } - { font-style [ style-css, ] } - { font-size [ size-css, ] } - } hash-apply - ] "" make ; + foreground [ fg-css, ] apply-style + background [ bg-css, ] apply-style + font [ font-css, ] apply-style + font-style [ style-css, ] apply-style + font-size [ size-css, ] apply-style + ] make-css ; : span-tag ( style quot -- ) over span-css-style dup empty? [ drop call ] [ call - ] if ; + ] if ; inline + +: format-html-span ( string style stream -- ) + [ + [ [ drop delegate-write ] span-tag ] object-link-tag + ] with-stream* ; + +TUPLE: html-span-stream ; + +M: html-span-stream stream-close + end-sub-stream format-html-span ; : border-css, ( border -- ) "border: 1px solid #" % hex-color, "; " % ; : padding-css, ( padding -- ) "padding: " % # "px; " % ; -: pre-css, ( -- ) - "white-space: pre; font-family: monospace; " % ; +: pre-css, ( margin -- ) + [ "white-space: pre; font-family: monospace; " % ] unless ; : div-css-style ( style -- str ) [ - H{ - { page-color [ bg-css, ] } - { border-color [ border-css, ] } - { border-width [ padding-css, ] } - { wrap-margin [ [ pre-css, ] unless ] } - } hash-apply - ] "" make ; + page-color [ bg-css, ] apply-style + border-color [ border-css, ] apply-style + border-width [ padding-css, ] apply-style + wrap-margin [ pre-css, ] apply-style + ] make-css ; : div-tag ( style quot -- ) swap div-css-style dup empty? [ drop call ] [
    call
    - ] if ; + ] if ; inline -: do-escaping ( string style -- string ) - html swap at [ chars>entities ] unless ; - -GENERIC: browser-link-href ( presented -- href ) - -M: object browser-link-href drop f ; - -: object-link-tag ( style quot -- ) - presented pick at browser-link-href - [ call ] [ call ] if* ; - -TUPLE: nested-stream ; - -: ( stream -- stream ) - nested-stream construct-delegate ; - -M: nested-stream stream-close drop ; - -TUPLE: html-stream ; - -: ( stream -- stream ) - html-stream construct-delegate ; - -M: html-stream stream-write1 ( char stream -- ) - >r 1string r> stream-write ; - -: delegate-write delegate stream-write ; - -M: html-stream stream-write ( str stream -- ) - >r chars>entities r> delegate-write ; - -: with-html-style ( quot style stream -- ) - [ [ swap span-tag ] object-link-tag ] with-stream* ; inline - -M: html-stream with-stream-style ( quot style stream -- ) - [ drop call ] -rot with-html-style ; - -M: html-stream stream-format ( str style stream -- ) - [ do-escaping stdio get delegate-write ] -rot - with-html-style ; - -: with-html-stream ( quot -- ) - stdio get swap with-stream* ; - -M: html-stream with-nested-stream ( quot style stream -- ) +: format-html-div ( string style stream -- ) [ - [ - [ - stdio get swap with-stream* - ] div-tag - ] object-link-tag + [ [ delegate-write ] div-tag ] object-link-tag ] with-stream* ; +TUPLE: html-block-stream ; + +M: html-block-stream stream-close ( quot style stream -- ) + end-sub-stream format-html-div ; + : border-spacing-css, "padding: " % first2 max 2 /i # "px; " % ; : table-style ( style -- str ) [ - H{ - { table-border [ border-css, ] } - { table-gap [ border-spacing-css, ] } - } hash-apply - ] "" make ; + table-border [ border-css, ] apply-style + table-gap [ border-spacing-css, ] apply-style + ] make-css ; : table-attrs ( style -- ) table-style " border-collapse: collapse;" append =style ; +: do-escaping ( string style -- string ) + html swap at [ chars>entities ] unless ; + +PRIVATE> + +! Stream protocol +M: html-stream stream-write1 ( char stream -- ) + >r 1string r> stream-write ; + +M: html-stream stream-write ( str stream -- ) + >r chars>entities r> delegate stream-write ; + +M: html-stream make-span-stream ( style stream -- stream' ) + html-span-stream ; + +M: html-stream stream-format ( str style stream -- ) + >r html over at [ >r chars>entities r> ] unless r> + format-html-span ; + +M: html-stream make-block-stream ( style stream -- stream' ) + html-block-stream ; + M: html-stream stream-write-table ( grid style stream -- ) [ swap [ [ ] curry* each ] curry* each
    - write-html + >string write-html
    ] with-stream* ; -M: html-stream make-table-cell ( quot style stream -- table-cell ) - 2drop [ with-html-stream ] string-out ; +M: html-stream make-cell-stream ( style stream -- stream' ) + (html-sub-stream) ; -M: html-stream stream-nl [
    ] with-stream* ; +M: html-stream stream-nl ( stream -- ) + [
    ] with-stream* ; -: default-css ( -- ) - ; +! Utilities +: with-html-stream ( quot -- ) + stdio get swap with-stream* ; : xhtml-preamble "" write-html "" write-html ; -: html-document* ( body-quot head-quot -- ) +: html-document ( body-quot head-quot -- ) #! head-quot is called to produce output to go #! in the html head portion of the document. #! body-quot is called to produce output to go #! in the html body portion of the document. xhtml-preamble - + call call ; - -: html-document ( title quot -- ) + +: default-css ( -- ) + ; + +: simple-html-document ( title quot -- ) swap [ write default-css - ] html-document* ; - -: simple-html-document ( title quot -- ) - swap [
     with-html-stream 
    ] html-document ; + ] html-document ; diff --git a/extra/http/server/resources/stylesheet.css b/extra/html/stylesheet.css similarity index 100% rename from extra/http/server/resources/stylesheet.css rename to extra/html/stylesheet.css diff --git a/extra/http/server/resources/prototype.js b/extra/http/server/resources/prototype.js deleted file mode 100644 index 0e85338bab..0000000000 --- a/extra/http/server/resources/prototype.js +++ /dev/null @@ -1,1781 +0,0 @@ -/* Prototype JavaScript framework, version 1.4.0 - * (c) 2005 Sam Stephenson - * - * Prototype is freely distributable under the terms of an MIT-style license. - * For details, see the Prototype web site: http://prototype.conio.net/ - * -/*--------------------------------------------------------------------------*/ - -var Prototype = { - Version: '1.4.0', - ScriptFragment: '(?:)((\n|\r|.)*?)(?:<\/script>)', - - emptyFunction: function() {}, - K: function(x) {return x} -} - -var Class = { - create: function() { - return function() { - this.initialize.apply(this, arguments); - } - } -} - -var Abstract = new Object(); - -Object.extend = function(destination, source) { - for (property in source) { - destination[property] = source[property]; - } - return destination; -} - -Object.inspect = function(object) { - try { - if (object == undefined) return 'undefined'; - if (object == null) return 'null'; - return object.inspect ? object.inspect() : object.toString(); - } catch (e) { - if (e instanceof RangeError) return '...'; - throw e; - } -} - -Function.prototype.bind = function() { - var __method = this, args = $A(arguments), object = args.shift(); - return function() { - return __method.apply(object, args.concat($A(arguments))); - } -} - -Function.prototype.bindAsEventListener = function(object) { - var __method = this; - return function(event) { - return __method.call(object, event || window.event); - } -} - -Object.extend(Number.prototype, { - toColorPart: function() { - var digits = this.toString(16); - if (this < 16) return '0' + digits; - return digits; - }, - - succ: function() { - return this + 1; - }, - - times: function(iterator) { - $R(0, this, true).each(iterator); - return this; - } -}); - -var Try = { - these: function() { - var returnValue; - - for (var i = 0; i < arguments.length; i++) { - var lambda = arguments[i]; - try { - returnValue = lambda(); - break; - } catch (e) {} - } - - return returnValue; - } -} - -/*--------------------------------------------------------------------------*/ - -var PeriodicalExecuter = Class.create(); -PeriodicalExecuter.prototype = { - initialize: function(callback, frequency) { - this.callback = callback; - this.frequency = frequency; - this.currentlyExecuting = false; - - this.registerCallback(); - }, - - registerCallback: function() { - setInterval(this.onTimerEvent.bind(this), this.frequency * 1000); - }, - - onTimerEvent: function() { - if (!this.currentlyExecuting) { - try { - this.currentlyExecuting = true; - this.callback(); - } finally { - this.currentlyExecuting = false; - } - } - } -} - -/*--------------------------------------------------------------------------*/ - -function $() { - var elements = new Array(); - - for (var i = 0; i < arguments.length; i++) { - var element = arguments[i]; - if (typeof element == 'string') - element = document.getElementById(element); - - if (arguments.length == 1) - return element; - - elements.push(element); - } - - return elements; -} -Object.extend(String.prototype, { - stripTags: function() { - return this.replace(/<\/?[^>]+>/gi, ''); - }, - - stripScripts: function() { - return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), ''); - }, - - extractScripts: function() { - var matchAll = new RegExp(Prototype.ScriptFragment, 'img'); - var matchOne = new RegExp(Prototype.ScriptFragment, 'im'); - return (this.match(matchAll) || []).map(function(scriptTag) { - return (scriptTag.match(matchOne) || ['', ''])[1]; - }); - }, - - evalScripts: function() { - return this.extractScripts().map(eval); - }, - - escapeHTML: function() { - var div = document.createElement('div'); - var text = document.createTextNode(this); - div.appendChild(text); - return div.innerHTML; - }, - - unescapeHTML: function() { - var div = document.createElement('div'); - div.innerHTML = this.stripTags(); - return div.childNodes[0] ? div.childNodes[0].nodeValue : ''; - }, - - toQueryParams: function() { - var pairs = this.match(/^\??(.*)$/)[1].split('&'); - return pairs.inject({}, function(params, pairString) { - var pair = pairString.split('='); - params[pair[0]] = pair[1]; - return params; - }); - }, - - toArray: function() { - return this.split(''); - }, - - camelize: function() { - var oStringList = this.split('-'); - if (oStringList.length == 1) return oStringList[0]; - - var camelizedString = this.indexOf('-') == 0 - ? oStringList[0].charAt(0).toUpperCase() + oStringList[0].substring(1) - : oStringList[0]; - - for (var i = 1, len = oStringList.length; i < len; i++) { - var s = oStringList[i]; - camelizedString += s.charAt(0).toUpperCase() + s.substring(1); - } - - return camelizedString; - }, - - inspect: function() { - return "'" + this.replace('\\', '\\\\').replace("'", '\\\'') + "'"; - } -}); - -String.prototype.parseQuery = String.prototype.toQueryParams; - -var $break = new Object(); -var $continue = new Object(); - -var Enumerable = { - each: function(iterator) { - var index = 0; - try { - this._each(function(value) { - try { - iterator(value, index++); - } catch (e) { - if (e != $continue) throw e; - } - }); - } catch (e) { - if (e != $break) throw e; - } - }, - - all: function(iterator) { - var result = true; - this.each(function(value, index) { - result = result && !!(iterator || Prototype.K)(value, index); - if (!result) throw $break; - }); - return result; - }, - - any: function(iterator) { - var result = true; - this.each(function(value, index) { - if (result = !!(iterator || Prototype.K)(value, index)) - throw $break; - }); - return result; - }, - - collect: function(iterator) { - var results = []; - this.each(function(value, index) { - results.push(iterator(value, index)); - }); - return results; - }, - - detect: function (iterator) { - var result; - this.each(function(value, index) { - if (iterator(value, index)) { - result = value; - throw $break; - } - }); - return result; - }, - - findAll: function(iterator) { - var results = []; - this.each(function(value, index) { - if (iterator(value, index)) - results.push(value); - }); - return results; - }, - - grep: function(pattern, iterator) { - var results = []; - this.each(function(value, index) { - var stringValue = value.toString(); - if (stringValue.match(pattern)) - results.push((iterator || Prototype.K)(value, index)); - }) - return results; - }, - - include: function(object) { - var found = false; - this.each(function(value) { - if (value == object) { - found = true; - throw $break; - } - }); - return found; - }, - - inject: function(memo, iterator) { - this.each(function(value, index) { - memo = iterator(memo, value, index); - }); - return memo; - }, - - invoke: function(method) { - var args = $A(arguments).slice(1); - return this.collect(function(value) { - return value[method].apply(value, args); - }); - }, - - max: function(iterator) { - var result; - this.each(function(value, index) { - value = (iterator || Prototype.K)(value, index); - if (value >= (result || value)) - result = value; - }); - return result; - }, - - min: function(iterator) { - var result; - this.each(function(value, index) { - value = (iterator || Prototype.K)(value, index); - if (value <= (result || value)) - result = value; - }); - return result; - }, - - partition: function(iterator) { - var trues = [], falses = []; - this.each(function(value, index) { - ((iterator || Prototype.K)(value, index) ? - trues : falses).push(value); - }); - return [trues, falses]; - }, - - pluck: function(property) { - var results = []; - this.each(function(value, index) { - results.push(value[property]); - }); - return results; - }, - - reject: function(iterator) { - var results = []; - this.each(function(value, index) { - if (!iterator(value, index)) - results.push(value); - }); - return results; - }, - - sortBy: function(iterator) { - return this.collect(function(value, index) { - return {value: value, criteria: iterator(value, index)}; - }).sort(function(left, right) { - var a = left.criteria, b = right.criteria; - return a < b ? -1 : a > b ? 1 : 0; - }).pluck('value'); - }, - - toArray: function() { - return this.collect(Prototype.K); - }, - - zip: function() { - var iterator = Prototype.K, args = $A(arguments); - if (typeof args.last() == 'function') - iterator = args.pop(); - - var collections = [this].concat(args).map($A); - return this.map(function(value, index) { - iterator(value = collections.pluck(index)); - return value; - }); - }, - - inspect: function() { - return '#'; - } -} - -Object.extend(Enumerable, { - map: Enumerable.collect, - find: Enumerable.detect, - select: Enumerable.findAll, - member: Enumerable.include, - entries: Enumerable.toArray -}); -var $A = Array.from = function(iterable) { - if (!iterable) return []; - if (iterable.toArray) { - return iterable.toArray(); - } else { - var results = []; - for (var i = 0; i < iterable.length; i++) - results.push(iterable[i]); - return results; - } -} - -Object.extend(Array.prototype, Enumerable); - -Array.prototype._reverse = Array.prototype.reverse; - -Object.extend(Array.prototype, { - _each: function(iterator) { - for (var i = 0; i < this.length; i++) - iterator(this[i]); - }, - - clear: function() { - this.length = 0; - return this; - }, - - first: function() { - return this[0]; - }, - - last: function() { - return this[this.length - 1]; - }, - - compact: function() { - return this.select(function(value) { - return value != undefined || value != null; - }); - }, - - flatten: function() { - return this.inject([], function(array, value) { - return array.concat(value.constructor == Array ? - value.flatten() : [value]); - }); - }, - - without: function() { - var values = $A(arguments); - return this.select(function(value) { - return !values.include(value); - }); - }, - - indexOf: function(object) { - for (var i = 0; i < this.length; i++) - if (this[i] == object) return i; - return -1; - }, - - reverse: function(inline) { - return (inline !== false ? this : this.toArray())._reverse(); - }, - - shift: function() { - var result = this[0]; - for (var i = 0; i < this.length - 1; i++) - this[i] = this[i + 1]; - this.length--; - return result; - }, - - inspect: function() { - return '[' + this.map(Object.inspect).join(', ') + ']'; - } -}); -var Hash = { - _each: function(iterator) { - for (key in this) { - var value = this[key]; - if (typeof value == 'function') continue; - - var pair = [key, value]; - pair.key = key; - pair.value = value; - iterator(pair); - } - }, - - keys: function() { - return this.pluck('key'); - }, - - values: function() { - return this.pluck('value'); - }, - - merge: function(hash) { - return $H(hash).inject($H(this), function(mergedHash, pair) { - mergedHash[pair.key] = pair.value; - return mergedHash; - }); - }, - - toQueryString: function() { - return this.map(function(pair) { - return pair.map(encodeURIComponent).join('='); - }).join('&'); - }, - - inspect: function() { - return '#'; - } -} - -function $H(object) { - var hash = Object.extend({}, object || {}); - Object.extend(hash, Enumerable); - Object.extend(hash, Hash); - return hash; -} -ObjectRange = Class.create(); -Object.extend(ObjectRange.prototype, Enumerable); -Object.extend(ObjectRange.prototype, { - initialize: function(start, end, exclusive) { - this.start = start; - this.end = end; - this.exclusive = exclusive; - }, - - _each: function(iterator) { - var value = this.start; - do { - iterator(value); - value = value.succ(); - } while (this.include(value)); - }, - - include: function(value) { - if (value < this.start) - return false; - if (this.exclusive) - return value < this.end; - return value <= this.end; - } -}); - -var $R = function(start, end, exclusive) { - return new ObjectRange(start, end, exclusive); -} - -var Ajax = { - getTransport: function() { - return Try.these( - function() {return new ActiveXObject('Msxml2.XMLHTTP')}, - function() {return new ActiveXObject('Microsoft.XMLHTTP')}, - function() {return new XMLHttpRequest()} - ) || false; - }, - - activeRequestCount: 0 -} - -Ajax.Responders = { - responders: [], - - _each: function(iterator) { - this.responders._each(iterator); - }, - - register: function(responderToAdd) { - if (!this.include(responderToAdd)) - this.responders.push(responderToAdd); - }, - - unregister: function(responderToRemove) { - this.responders = this.responders.without(responderToRemove); - }, - - dispatch: function(callback, request, transport, json) { - this.each(function(responder) { - if (responder[callback] && typeof responder[callback] == 'function') { - try { - responder[callback].apply(responder, [request, transport, json]); - } catch (e) {} - } - }); - } -}; - -Object.extend(Ajax.Responders, Enumerable); - -Ajax.Responders.register({ - onCreate: function() { - Ajax.activeRequestCount++; - }, - - onComplete: function() { - Ajax.activeRequestCount--; - } -}); - -Ajax.Base = function() {}; -Ajax.Base.prototype = { - setOptions: function(options) { - this.options = { - method: 'post', - asynchronous: true, - parameters: '' - } - Object.extend(this.options, options || {}); - }, - - responseIsSuccess: function() { - return this.transport.status == undefined - || this.transport.status == 0 - || (this.transport.status >= 200 && this.transport.status < 300); - }, - - responseIsFailure: function() { - return !this.responseIsSuccess(); - } -} - -Ajax.Request = Class.create(); -Ajax.Request.Events = - ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete']; - -Ajax.Request.prototype = Object.extend(new Ajax.Base(), { - initialize: function(url, options) { - this.transport = Ajax.getTransport(); - this.setOptions(options); - this.request(url); - }, - - request: function(url) { - var parameters = this.options.parameters || ''; - if (parameters.length > 0) parameters += '&_='; - - try { - this.url = url; - if (this.options.method == 'get' && parameters.length > 0) - this.url += (this.url.match(/\?/) ? '&' : '?') + parameters; - - Ajax.Responders.dispatch('onCreate', this, this.transport); - - this.transport.open(this.options.method, this.url, - this.options.asynchronous); - - if (this.options.asynchronous) { - this.transport.onreadystatechange = this.onStateChange.bind(this); - setTimeout((function() {this.respondToReadyState(1)}).bind(this), 10); - } - - this.setRequestHeaders(); - - var body = this.options.postBody ? this.options.postBody : parameters; - this.transport.send(this.options.method == 'post' ? body : null); - - } catch (e) { - this.dispatchException(e); - } - }, - - setRequestHeaders: function() { - var requestHeaders = - ['X-Requested-With', 'XMLHttpRequest', - 'X-Prototype-Version', Prototype.Version]; - - if (this.options.method == 'post') { - requestHeaders.push('Content-type', - 'application/x-www-form-urlencoded'); - - /* Force "Connection: close" for Mozilla browsers to work around - * a bug where XMLHttpReqeuest sends an incorrect Content-length - * header. See Mozilla Bugzilla #246651. - */ - if (this.transport.overrideMimeType) - requestHeaders.push('Connection', 'close'); - } - - if (this.options.requestHeaders) - requestHeaders.push.apply(requestHeaders, this.options.requestHeaders); - - for (var i = 0; i < requestHeaders.length; i += 2) - this.transport.setRequestHeader(requestHeaders[i], requestHeaders[i+1]); - }, - - onStateChange: function() { - var readyState = this.transport.readyState; - if (readyState != 1) - this.respondToReadyState(this.transport.readyState); - }, - - header: function(name) { - try { - return this.transport.getResponseHeader(name); - } catch (e) {} - }, - - evalJSON: function() { - try { - return eval(this.header('X-JSON')); - } catch (e) {} - }, - - evalResponse: function() { - try { - return eval(this.transport.responseText); - } catch (e) { - this.dispatchException(e); - } - }, - - respondToReadyState: function(readyState) { - var event = Ajax.Request.Events[readyState]; - var transport = this.transport, json = this.evalJSON(); - - if (event == 'Complete') { - try { - (this.options['on' + this.transport.status] - || this.options['on' + (this.responseIsSuccess() ? 'Success' : 'Failure')] - || Prototype.emptyFunction)(transport, json); - } catch (e) { - this.dispatchException(e); - } - - if ((this.header('Content-type') || '').match(/^text\/javascript/i)) - this.evalResponse(); - } - - try { - (this.options['on' + event] || Prototype.emptyFunction)(transport, json); - Ajax.Responders.dispatch('on' + event, this, transport, json); - } catch (e) { - this.dispatchException(e); - } - - /* Avoid memory leak in MSIE: clean up the oncomplete event handler */ - if (event == 'Complete') - this.transport.onreadystatechange = Prototype.emptyFunction; - }, - - dispatchException: function(exception) { - (this.options.onException || Prototype.emptyFunction)(this, exception); - Ajax.Responders.dispatch('onException', this, exception); - } -}); - -Ajax.Updater = Class.create(); - -Object.extend(Object.extend(Ajax.Updater.prototype, Ajax.Request.prototype), { - initialize: function(container, url, options) { - this.containers = { - success: container.success ? $(container.success) : $(container), - failure: container.failure ? $(container.failure) : - (container.success ? null : $(container)) - } - - this.transport = Ajax.getTransport(); - this.setOptions(options); - - var onComplete = this.options.onComplete || Prototype.emptyFunction; - this.options.onComplete = (function(transport, object) { - this.updateContent(); - onComplete(transport, object); - }).bind(this); - - this.request(url); - }, - - updateContent: function() { - var receiver = this.responseIsSuccess() ? - this.containers.success : this.containers.failure; - var response = this.transport.responseText; - - if (!this.options.evalScripts) - response = response.stripScripts(); - - if (receiver) { - if (this.options.insertion) { - new this.options.insertion(receiver, response); - } else { - Element.update(receiver, response); - } - } - - if (this.responseIsSuccess()) { - if (this.onComplete) - setTimeout(this.onComplete.bind(this), 10); - } - } -}); - -Ajax.PeriodicalUpdater = Class.create(); -Ajax.PeriodicalUpdater.prototype = Object.extend(new Ajax.Base(), { - initialize: function(container, url, options) { - this.setOptions(options); - this.onComplete = this.options.onComplete; - - this.frequency = (this.options.frequency || 2); - this.decay = (this.options.decay || 1); - - this.updater = {}; - this.container = container; - this.url = url; - - this.start(); - }, - - start: function() { - this.options.onComplete = this.updateComplete.bind(this); - this.onTimerEvent(); - }, - - stop: function() { - this.updater.onComplete = undefined; - clearTimeout(this.timer); - (this.onComplete || Prototype.emptyFunction).apply(this, arguments); - }, - - updateComplete: function(request) { - if (this.options.decay) { - this.decay = (request.responseText == this.lastText ? - this.decay * this.options.decay : 1); - - this.lastText = request.responseText; - } - this.timer = setTimeout(this.onTimerEvent.bind(this), - this.decay * this.frequency * 1000); - }, - - onTimerEvent: function() { - this.updater = new Ajax.Updater(this.container, this.url, this.options); - } -}); -document.getElementsByClassName = function(className, parentElement) { - var children = ($(parentElement) || document.body).getElementsByTagName('*'); - return $A(children).inject([], function(elements, child) { - if (child.className.match(new RegExp("(^|\\s)" + className + "(\\s|$)"))) - elements.push(child); - return elements; - }); -} - -/*--------------------------------------------------------------------------*/ - -if (!window.Element) { - var Element = new Object(); -} - -Object.extend(Element, { - visible: function(element) { - return $(element).style.display != 'none'; - }, - - toggle: function() { - for (var i = 0; i < arguments.length; i++) { - var element = $(arguments[i]); - Element[Element.visible(element) ? 'hide' : 'show'](element); - } - }, - - hide: function() { - for (var i = 0; i < arguments.length; i++) { - var element = $(arguments[i]); - element.style.display = 'none'; - } - }, - - show: function() { - for (var i = 0; i < arguments.length; i++) { - var element = $(arguments[i]); - element.style.display = ''; - } - }, - - remove: function(element) { - element = $(element); - element.parentNode.removeChild(element); - }, - - update: function(element, html) { - $(element).innerHTML = html.stripScripts(); - setTimeout(function() {html.evalScripts()}, 10); - }, - - getHeight: function(element) { - element = $(element); - return element.offsetHeight; - }, - - classNames: function(element) { - return new Element.ClassNames(element); - }, - - hasClassName: function(element, className) { - if (!(element = $(element))) return; - return Element.classNames(element).include(className); - }, - - addClassName: function(element, className) { - if (!(element = $(element))) return; - return Element.classNames(element).add(className); - }, - - removeClassName: function(element, className) { - if (!(element = $(element))) return; - return Element.classNames(element).remove(className); - }, - - // removes whitespace-only text node children - cleanWhitespace: function(element) { - element = $(element); - for (var i = 0; i < element.childNodes.length; i++) { - var node = element.childNodes[i]; - if (node.nodeType == 3 && !/\S/.test(node.nodeValue)) - Element.remove(node); - } - }, - - empty: function(element) { - return $(element).innerHTML.match(/^\s*$/); - }, - - scrollTo: function(element) { - element = $(element); - var x = element.x ? element.x : element.offsetLeft, - y = element.y ? element.y : element.offsetTop; - window.scrollTo(x, y); - }, - - getStyle: function(element, style) { - element = $(element); - var value = element.style[style.camelize()]; - if (!value) { - if (document.defaultView && document.defaultView.getComputedStyle) { - var css = document.defaultView.getComputedStyle(element, null); - value = css ? css.getPropertyValue(style) : null; - } else if (element.currentStyle) { - value = element.currentStyle[style.camelize()]; - } - } - - if (window.opera && ['left', 'top', 'right', 'bottom'].include(style)) - if (Element.getStyle(element, 'position') == 'static') value = 'auto'; - - return value == 'auto' ? null : value; - }, - - setStyle: function(element, style) { - element = $(element); - for (name in style) - element.style[name.camelize()] = style[name]; - }, - - getDimensions: function(element) { - element = $(element); - if (Element.getStyle(element, 'display') != 'none') - return {width: element.offsetWidth, height: element.offsetHeight}; - - // All *Width and *Height properties give 0 on elements with display none, - // so enable the element temporarily - var els = element.style; - var originalVisibility = els.visibility; - var originalPosition = els.position; - els.visibility = 'hidden'; - els.position = 'absolute'; - els.display = ''; - var originalWidth = element.clientWidth; - var originalHeight = element.clientHeight; - els.display = 'none'; - els.position = originalPosition; - els.visibility = originalVisibility; - return {width: originalWidth, height: originalHeight}; - }, - - makePositioned: function(element) { - element = $(element); - var pos = Element.getStyle(element, 'position'); - if (pos == 'static' || !pos) { - element._madePositioned = true; - element.style.position = 'relative'; - // Opera returns the offset relative to the positioning context, when an - // element is position relative but top and left have not been defined - if (window.opera) { - element.style.top = 0; - element.style.left = 0; - } - } - }, - - undoPositioned: function(element) { - element = $(element); - if (element._madePositioned) { - element._madePositioned = undefined; - element.style.position = - element.style.top = - element.style.left = - element.style.bottom = - element.style.right = ''; - } - }, - - makeClipping: function(element) { - element = $(element); - if (element._overflow) return; - element._overflow = element.style.overflow; - if ((Element.getStyle(element, 'overflow') || 'visible') != 'hidden') - element.style.overflow = 'hidden'; - }, - - undoClipping: function(element) { - element = $(element); - if (element._overflow) return; - element.style.overflow = element._overflow; - element._overflow = undefined; - } -}); - -var Toggle = new Object(); -Toggle.display = Element.toggle; - -/*--------------------------------------------------------------------------*/ - -Abstract.Insertion = function(adjacency) { - this.adjacency = adjacency; -} - -Abstract.Insertion.prototype = { - initialize: function(element, content) { - this.element = $(element); - this.content = content.stripScripts(); - - if (this.adjacency && this.element.insertAdjacentHTML) { - try { - this.element.insertAdjacentHTML(this.adjacency, this.content); - } catch (e) { - if (this.element.tagName.toLowerCase() == 'tbody') { - this.insertContent(this.contentFromAnonymousTable()); - } else { - throw e; - } - } - } else { - this.range = this.element.ownerDocument.createRange(); - if (this.initializeRange) this.initializeRange(); - this.insertContent([this.range.createContextualFragment(this.content)]); - } - - setTimeout(function() {content.evalScripts()}, 10); - }, - - contentFromAnonymousTable: function() { - var div = document.createElement('div'); - div.innerHTML = '' + this.content + '
    '; - return $A(div.childNodes[0].childNodes[0].childNodes); - } -} - -var Insertion = new Object(); - -Insertion.Before = Class.create(); -Insertion.Before.prototype = Object.extend(new Abstract.Insertion('beforeBegin'), { - initializeRange: function() { - this.range.setStartBefore(this.element); - }, - - insertContent: function(fragments) { - fragments.each((function(fragment) { - this.element.parentNode.insertBefore(fragment, this.element); - }).bind(this)); - } -}); - -Insertion.Top = Class.create(); -Insertion.Top.prototype = Object.extend(new Abstract.Insertion('afterBegin'), { - initializeRange: function() { - this.range.selectNodeContents(this.element); - this.range.collapse(true); - }, - - insertContent: function(fragments) { - fragments.reverse(false).each((function(fragment) { - this.element.insertBefore(fragment, this.element.firstChild); - }).bind(this)); - } -}); - -Insertion.Bottom = Class.create(); -Insertion.Bottom.prototype = Object.extend(new Abstract.Insertion('beforeEnd'), { - initializeRange: function() { - this.range.selectNodeContents(this.element); - this.range.collapse(this.element); - }, - - insertContent: function(fragments) { - fragments.each((function(fragment) { - this.element.appendChild(fragment); - }).bind(this)); - } -}); - -Insertion.After = Class.create(); -Insertion.After.prototype = Object.extend(new Abstract.Insertion('afterEnd'), { - initializeRange: function() { - this.range.setStartAfter(this.element); - }, - - insertContent: function(fragments) { - fragments.each((function(fragment) { - this.element.parentNode.insertBefore(fragment, - this.element.nextSibling); - }).bind(this)); - } -}); - -/*--------------------------------------------------------------------------*/ - -Element.ClassNames = Class.create(); -Element.ClassNames.prototype = { - initialize: function(element) { - this.element = $(element); - }, - - _each: function(iterator) { - this.element.className.split(/\s+/).select(function(name) { - return name.length > 0; - })._each(iterator); - }, - - set: function(className) { - this.element.className = className; - }, - - add: function(classNameToAdd) { - if (this.include(classNameToAdd)) return; - this.set(this.toArray().concat(classNameToAdd).join(' ')); - }, - - remove: function(classNameToRemove) { - if (!this.include(classNameToRemove)) return; - this.set(this.select(function(className) { - return className != classNameToRemove; - }).join(' ')); - }, - - toString: function() { - return this.toArray().join(' '); - } -} - -Object.extend(Element.ClassNames.prototype, Enumerable); -var Field = { - clear: function() { - for (var i = 0; i < arguments.length; i++) - $(arguments[i]).value = ''; - }, - - focus: function(element) { - $(element).focus(); - }, - - present: function() { - for (var i = 0; i < arguments.length; i++) - if ($(arguments[i]).value == '') return false; - return true; - }, - - select: function(element) { - $(element).select(); - }, - - activate: function(element) { - element = $(element); - element.focus(); - if (element.select) - element.select(); - } -} - -/*--------------------------------------------------------------------------*/ - -var Form = { - serialize: function(form) { - var elements = Form.getElements($(form)); - var queryComponents = new Array(); - - for (var i = 0; i < elements.length; i++) { - var queryComponent = Form.Element.serialize(elements[i]); - if (queryComponent) - queryComponents.push(queryComponent); - } - - return queryComponents.join('&'); - }, - - getElements: function(form) { - form = $(form); - var elements = new Array(); - - for (tagName in Form.Element.Serializers) { - var tagElements = form.getElementsByTagName(tagName); - for (var j = 0; j < tagElements.length; j++) - elements.push(tagElements[j]); - } - return elements; - }, - - getInputs: function(form, typeName, name) { - form = $(form); - var inputs = form.getElementsByTagName('input'); - - if (!typeName && !name) - return inputs; - - var matchingInputs = new Array(); - for (var i = 0; i < inputs.length; i++) { - var input = inputs[i]; - if ((typeName && input.type != typeName) || - (name && input.name != name)) - continue; - matchingInputs.push(input); - } - - return matchingInputs; - }, - - disable: function(form) { - var elements = Form.getElements(form); - for (var i = 0; i < elements.length; i++) { - var element = elements[i]; - element.blur(); - element.disabled = 'true'; - } - }, - - enable: function(form) { - var elements = Form.getElements(form); - for (var i = 0; i < elements.length; i++) { - var element = elements[i]; - element.disabled = ''; - } - }, - - findFirstElement: function(form) { - return Form.getElements(form).find(function(element) { - return element.type != 'hidden' && !element.disabled && - ['input', 'select', 'textarea'].include(element.tagName.toLowerCase()); - }); - }, - - focusFirstElement: function(form) { - Field.activate(Form.findFirstElement(form)); - }, - - reset: function(form) { - $(form).reset(); - } -} - -Form.Element = { - serialize: function(element) { - element = $(element); - var method = element.tagName.toLowerCase(); - var parameter = Form.Element.Serializers[method](element); - - if (parameter) { - var key = encodeURIComponent(parameter[0]); - if (key.length == 0) return; - - if (parameter[1].constructor != Array) - parameter[1] = [parameter[1]]; - - return parameter[1].map(function(value) { - return key + '=' + encodeURIComponent(value); - }).join('&'); - } - }, - - getValue: function(element) { - element = $(element); - var method = element.tagName.toLowerCase(); - var parameter = Form.Element.Serializers[method](element); - - if (parameter) - return parameter[1]; - } -} - -Form.Element.Serializers = { - input: function(element) { - switch (element.type.toLowerCase()) { - case 'submit': - case 'hidden': - case 'password': - case 'text': - return Form.Element.Serializers.textarea(element); - case 'checkbox': - case 'radio': - return Form.Element.Serializers.inputSelector(element); - } - return false; - }, - - inputSelector: function(element) { - if (element.checked) - return [element.name, element.value]; - }, - - textarea: function(element) { - return [element.name, element.value]; - }, - - select: function(element) { - return Form.Element.Serializers[element.type == 'select-one' ? - 'selectOne' : 'selectMany'](element); - }, - - selectOne: function(element) { - var value = '', opt, index = element.selectedIndex; - if (index >= 0) { - opt = element.options[index]; - value = opt.value; - if (!value && !('value' in opt)) - value = opt.text; - } - return [element.name, value]; - }, - - selectMany: function(element) { - var value = new Array(); - for (var i = 0; i < element.length; i++) { - var opt = element.options[i]; - if (opt.selected) { - var optValue = opt.value; - if (!optValue && !('value' in opt)) - optValue = opt.text; - value.push(optValue); - } - } - return [element.name, value]; - } -} - -/*--------------------------------------------------------------------------*/ - -var $F = Form.Element.getValue; - -/*--------------------------------------------------------------------------*/ - -Abstract.TimedObserver = function() {} -Abstract.TimedObserver.prototype = { - initialize: function(element, frequency, callback) { - this.frequency = frequency; - this.element = $(element); - this.callback = callback; - - this.lastValue = this.getValue(); - this.registerCallback(); - }, - - registerCallback: function() { - setInterval(this.onTimerEvent.bind(this), this.frequency * 1000); - }, - - onTimerEvent: function() { - var value = this.getValue(); - if (this.lastValue != value) { - this.callback(this.element, value); - this.lastValue = value; - } - } -} - -Form.Element.Observer = Class.create(); -Form.Element.Observer.prototype = Object.extend(new Abstract.TimedObserver(), { - getValue: function() { - return Form.Element.getValue(this.element); - } -}); - -Form.Observer = Class.create(); -Form.Observer.prototype = Object.extend(new Abstract.TimedObserver(), { - getValue: function() { - return Form.serialize(this.element); - } -}); - -/*--------------------------------------------------------------------------*/ - -Abstract.EventObserver = function() {} -Abstract.EventObserver.prototype = { - initialize: function(element, callback) { - this.element = $(element); - this.callback = callback; - - this.lastValue = this.getValue(); - if (this.element.tagName.toLowerCase() == 'form') - this.registerFormCallbacks(); - else - this.registerCallback(this.element); - }, - - onElementEvent: function() { - var value = this.getValue(); - if (this.lastValue != value) { - this.callback(this.element, value); - this.lastValue = value; - } - }, - - registerFormCallbacks: function() { - var elements = Form.getElements(this.element); - for (var i = 0; i < elements.length; i++) - this.registerCallback(elements[i]); - }, - - registerCallback: function(element) { - if (element.type) { - switch (element.type.toLowerCase()) { - case 'checkbox': - case 'radio': - Event.observe(element, 'click', this.onElementEvent.bind(this)); - break; - case 'password': - case 'text': - case 'textarea': - case 'select-one': - case 'select-multiple': - Event.observe(element, 'change', this.onElementEvent.bind(this)); - break; - } - } - } -} - -Form.Element.EventObserver = Class.create(); -Form.Element.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), { - getValue: function() { - return Form.Element.getValue(this.element); - } -}); - -Form.EventObserver = Class.create(); -Form.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), { - getValue: function() { - return Form.serialize(this.element); - } -}); -if (!window.Event) { - var Event = new Object(); -} - -Object.extend(Event, { - KEY_BACKSPACE: 8, - KEY_TAB: 9, - KEY_RETURN: 13, - KEY_ESC: 27, - KEY_LEFT: 37, - KEY_UP: 38, - KEY_RIGHT: 39, - KEY_DOWN: 40, - KEY_DELETE: 46, - - element: function(event) { - return event.target || event.srcElement; - }, - - isLeftClick: function(event) { - return (((event.which) && (event.which == 1)) || - ((event.button) && (event.button == 1))); - }, - - pointerX: function(event) { - return event.pageX || (event.clientX + - (document.documentElement.scrollLeft || document.body.scrollLeft)); - }, - - pointerY: function(event) { - return event.pageY || (event.clientY + - (document.documentElement.scrollTop || document.body.scrollTop)); - }, - - stop: function(event) { - if (event.preventDefault) { - event.preventDefault(); - event.stopPropagation(); - } else { - event.returnValue = false; - event.cancelBubble = true; - } - }, - - // find the first node with the given tagName, starting from the - // node the event was triggered on; traverses the DOM upwards - findElement: function(event, tagName) { - var element = Event.element(event); - while (element.parentNode && (!element.tagName || - (element.tagName.toUpperCase() != tagName.toUpperCase()))) - element = element.parentNode; - return element; - }, - - observers: false, - - _observeAndCache: function(element, name, observer, useCapture) { - if (!this.observers) this.observers = []; - if (element.addEventListener) { - this.observers.push([element, name, observer, useCapture]); - element.addEventListener(name, observer, useCapture); - } else if (element.attachEvent) { - this.observers.push([element, name, observer, useCapture]); - element.attachEvent('on' + name, observer); - } - }, - - unloadCache: function() { - if (!Event.observers) return; - for (var i = 0; i < Event.observers.length; i++) { - Event.stopObserving.apply(this, Event.observers[i]); - Event.observers[i][0] = null; - } - Event.observers = false; - }, - - observe: function(element, name, observer, useCapture) { - var element = $(element); - useCapture = useCapture || false; - - if (name == 'keypress' && - (navigator.appVersion.match(/Konqueror|Safari|KHTML/) - || element.attachEvent)) - name = 'keydown'; - - this._observeAndCache(element, name, observer, useCapture); - }, - - stopObserving: function(element, name, observer, useCapture) { - var element = $(element); - useCapture = useCapture || false; - - if (name == 'keypress' && - (navigator.appVersion.match(/Konqueror|Safari|KHTML/) - || element.detachEvent)) - name = 'keydown'; - - if (element.removeEventListener) { - element.removeEventListener(name, observer, useCapture); - } else if (element.detachEvent) { - element.detachEvent('on' + name, observer); - } - } -}); - -/* prevent memory leaks in IE */ -Event.observe(window, 'unload', Event.unloadCache, false); -var Position = { - // set to true if needed, warning: firefox performance problems - // NOT neeeded for page scrolling, only if draggable contained in - // scrollable elements - includeScrollOffsets: false, - - // must be called before calling withinIncludingScrolloffset, every time the - // page is scrolled - prepare: function() { - this.deltaX = window.pageXOffset - || document.documentElement.scrollLeft - || document.body.scrollLeft - || 0; - this.deltaY = window.pageYOffset - || document.documentElement.scrollTop - || document.body.scrollTop - || 0; - }, - - realOffset: function(element) { - var valueT = 0, valueL = 0; - do { - valueT += element.scrollTop || 0; - valueL += element.scrollLeft || 0; - element = element.parentNode; - } while (element); - return [valueL, valueT]; - }, - - cumulativeOffset: function(element) { - var valueT = 0, valueL = 0; - do { - valueT += element.offsetTop || 0; - valueL += element.offsetLeft || 0; - element = element.offsetParent; - } while (element); - return [valueL, valueT]; - }, - - positionedOffset: function(element) { - var valueT = 0, valueL = 0; - do { - valueT += element.offsetTop || 0; - valueL += element.offsetLeft || 0; - element = element.offsetParent; - if (element) { - p = Element.getStyle(element, 'position'); - if (p == 'relative' || p == 'absolute') break; - } - } while (element); - return [valueL, valueT]; - }, - - offsetParent: function(element) { - if (element.offsetParent) return element.offsetParent; - if (element == document.body) return element; - - while ((element = element.parentNode) && element != document.body) - if (Element.getStyle(element, 'position') != 'static') - return element; - - return document.body; - }, - - // caches x/y coordinate pair to use with overlap - within: function(element, x, y) { - if (this.includeScrollOffsets) - return this.withinIncludingScrolloffsets(element, x, y); - this.xcomp = x; - this.ycomp = y; - this.offset = this.cumulativeOffset(element); - - return (y >= this.offset[1] && - y < this.offset[1] + element.offsetHeight && - x >= this.offset[0] && - x < this.offset[0] + element.offsetWidth); - }, - - withinIncludingScrolloffsets: function(element, x, y) { - var offsetcache = this.realOffset(element); - - this.xcomp = x + offsetcache[0] - this.deltaX; - this.ycomp = y + offsetcache[1] - this.deltaY; - this.offset = this.cumulativeOffset(element); - - return (this.ycomp >= this.offset[1] && - this.ycomp < this.offset[1] + element.offsetHeight && - this.xcomp >= this.offset[0] && - this.xcomp < this.offset[0] + element.offsetWidth); - }, - - // within must be called directly before - overlap: function(mode, element) { - if (!mode) return 0; - if (mode == 'vertical') - return ((this.offset[1] + element.offsetHeight) - this.ycomp) / - element.offsetHeight; - if (mode == 'horizontal') - return ((this.offset[0] + element.offsetWidth) - this.xcomp) / - element.offsetWidth; - }, - - clone: function(source, target) { - source = $(source); - target = $(target); - target.style.position = 'absolute'; - var offsets = this.cumulativeOffset(source); - target.style.top = offsets[1] + 'px'; - target.style.left = offsets[0] + 'px'; - target.style.width = source.offsetWidth + 'px'; - target.style.height = source.offsetHeight + 'px'; - }, - - page: function(forElement) { - var valueT = 0, valueL = 0; - - var element = forElement; - do { - valueT += element.offsetTop || 0; - valueL += element.offsetLeft || 0; - - // Safari fix - if (element.offsetParent==document.body) - if (Element.getStyle(element,'position')=='absolute') break; - - } while (element = element.offsetParent); - - element = forElement; - do { - valueT -= element.scrollTop || 0; - valueL -= element.scrollLeft || 0; - } while (element = element.parentNode); - - return [valueL, valueT]; - }, - - clone: function(source, target) { - var options = Object.extend({ - setLeft: true, - setTop: true, - setWidth: true, - setHeight: true, - offsetTop: 0, - offsetLeft: 0 - }, arguments[2] || {}) - - // find page position of source - source = $(source); - var p = Position.page(source); - - // find coordinate system to use - target = $(target); - var delta = [0, 0]; - var parent = null; - // delta [0,0] will do fine with position: fixed elements, - // position:absolute needs offsetParent deltas - if (Element.getStyle(target,'position') == 'absolute') { - parent = Position.offsetParent(target); - delta = Position.page(parent); - } - - // correct by body offsets (fixes Safari) - if (parent == document.body) { - delta[0] -= document.body.offsetLeft; - delta[1] -= document.body.offsetTop; - } - - // set position - if(options.setLeft) target.style.left = (p[0] - delta[0] + options.offsetLeft) + 'px'; - if(options.setTop) target.style.top = (p[1] - delta[1] + options.offsetTop) + 'px'; - if(options.setWidth) target.style.width = source.offsetWidth + 'px'; - if(options.setHeight) target.style.height = source.offsetHeight + 'px'; - }, - - absolutize: function(element) { - element = $(element); - if (element.style.position == 'absolute') return; - Position.prepare(); - - var offsets = Position.positionedOffset(element); - var top = offsets[1]; - var left = offsets[0]; - var width = element.clientWidth; - var height = element.clientHeight; - - element._originalLeft = left - parseFloat(element.style.left || 0); - element._originalTop = top - parseFloat(element.style.top || 0); - element._originalWidth = element.style.width; - element._originalHeight = element.style.height; - - element.style.position = 'absolute'; - element.style.top = top + 'px';; - element.style.left = left + 'px';; - element.style.width = width + 'px';; - element.style.height = height + 'px';; - }, - - relativize: function(element) { - element = $(element); - if (element.style.position == 'relative') return; - Position.prepare(); - - element.style.position = 'relative'; - var top = parseFloat(element.style.top || 0) - (element._originalTop || 0); - var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0); - - element.style.top = top + 'px'; - element.style.left = left + 'px'; - element.style.height = element._originalHeight; - element.style.width = element._originalWidth; - } -} - -// Safari returns margins on body which is incorrect if the child is absolutely -// positioned. For performance reasons, redefine Position.cumulativeOffset for -// KHTML/WebKit only. -if (/Konqueror|Safari|KHTML/.test(navigator.userAgent)) { - Position.cumulativeOffset = function(element) { - var valueT = 0, valueL = 0; - do { - valueT += element.offsetTop || 0; - valueL += element.offsetLeft || 0; - if (element.offsetParent == document.body) - if (Element.getStyle(element, 'position') == 'absolute') break; - - element = element.offsetParent; - } while (element); - - return [valueL, valueT]; - } -} \ No newline at end of file From 376097d2ff2d8cb924e61f11e574d3b84cb92982 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Tue, 25 Sep 2007 20:31:06 -0400 Subject: [PATCH 07/21] Stack effect fixes --- extra/concurrency/concurrency.factor | 2 +- extra/xml/utilities/utilities.factor | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/extra/concurrency/concurrency.factor b/extra/concurrency/concurrency.factor index 391e6b4c4b..32ae3e5940 100644 --- a/extra/concurrency/concurrency.factor +++ b/extra/concurrency/concurrency.factor @@ -239,7 +239,7 @@ PRIVATE> "Exiting process: " write self process-pid print ] curry spawn-link ; -: server-cc ( -- cc | process ) +: server-cc ( -- cc|process ) #! Captures the current continuation and returns the value. #! If that CC is called with a process on the stack it will #! set 'self' for the current process to it. Otherwise it will diff --git a/extra/xml/utilities/utilities.factor b/extra/xml/utilities/utilities.factor index f88d4c5863..303de4295e 100644 --- a/extra/xml/utilities/utilities.factor +++ b/extra/xml/utilities/utilities.factor @@ -10,9 +10,9 @@ IN: xml.utilities TUPLE: process-missing process tag ; M: process-missing error. "Tag <" write - process-missing-tag print-name + dup process-missing-tag print-name "> not implemented on process process " write - dup process-missing-process word-name print ; + process-missing-process word-name print ; : run-process ( tag word -- ) 2dup "xtable" word-prop From d40b52f4ef0d88815bd7122aa8ac2f1084c3da7b Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Tue, 25 Sep 2007 20:31:32 -0400 Subject: [PATCH 08/21] Update HTTP server for HTML stream changes --- extra/furnace/furnace.factor | 6 ++-- extra/http/http.factor | 2 +- .../continuation/examples/examples.factor | 10 +++--- extra/http/server/responders/file/file.factor | 33 +++++++++++-------- .../http/server/responders/responders.factor | 9 ++--- extra/webapps/help/help.factor | 15 +++++---- 6 files changed, 42 insertions(+), 33 deletions(-) diff --git a/extra/furnace/furnace.factor b/extra/furnace/furnace.factor index 8a475b98db..330c486817 100644 --- a/extra/furnace/furnace.factor +++ b/extra/furnace/furnace.factor @@ -118,18 +118,18 @@ SYMBOL: model : render-page* ( model body-template head-template -- ) [ - [ render-template ] [ f rot render-template ] html-document* + [ render-template ] [ f rot render-template ] html-document ] serve-html ; : render-titled-page* ( model body-template head-template title -- ) [ - [ render-template ] swap [ write f rot render-template ] curry html-document* + [ render-template ] swap [ write f rot render-template ] curry html-document ] serve-html ; : render-page ( model template title -- ) [ - [ render-template ] html-document + [ render-template ] simple-html-document ] serve-html ; : web-app ( name default path -- ) diff --git a/extra/http/http.factor b/extra/http/http.factor index 687fa807f5..a358c449af 100644 --- a/extra/http/http.factor +++ b/extra/http/http.factor @@ -7,7 +7,7 @@ IN: http : header-line ( line -- ) ": " split1 dup [ swap set ] [ 2drop ] if ; -: (read-header) ( hash -- hash ) +: (read-header) ( -- ) readln dup empty? [ drop ] [ header-line (read-header) ] if ; diff --git a/extra/http/server/responders/continuation/examples/examples.factor b/extra/http/server/responders/continuation/examples/examples.factor index 2a2eae72d7..e6abcc7a72 100644 --- a/extra/http/server/responders/continuation/examples/examples.factor +++ b/extra/http/server/responders/continuation/examples/examples.factor @@ -34,7 +34,7 @@ IN: http.server.responders.continuation.examples

    over write

    swap [ "Next" write - ] html-document + ] simple-html-document ] show 2drop ; : display-get-name-page ( -- name ) @@ -47,7 +47,7 @@ IN: http.server.responders.continuation.examples - ] html-document + ] simple-html-document ] show "name" swap at ; : test-cont-responder ( -- ) @@ -71,7 +71,7 @@ IN: http.server.responders.continuation.examples
  1. "Test responder1" [ test-cont-responder ] quot-href
  2. "Test responder2" [ test-cont-responder2 ] quot-href
  3. @@^J)~UI-*ZXF9r-yZ&Jmr&CQ+IKC_?_td z(y}L#^YRsJf%rX_l=N@bCM45(oDm(w8E!(`Az*1$+||4&s;sUm>FVL$slMCAWB=MQ zS|mxpS@>la0dO2ljpUP4{Fg(0$2Z(A9}_38sXui1`4?8+Dc#+~*R{3Hj}-`iwO3U_ zfu&8PZSA&rRIDG?t2KGvKCdt)@3ruD{Q+9&Bj5nJ)ZkMOFwbjcpBI-Lo zy^(~5#v!S?c(Kw@w=_AYti>lmc#Wqne!aQ7$MSy^UuKvU4(#pfXX0}7r3PQj*ODWH zz@TmXjFTeygGW>vWvh$cvdybI+_lk`zL)nLq2vt@oDb@OjmrZrngIVr{DPv7i%jN} z_9ML;d;0rtd4_#2_-N}nvSOb=^g%*B?D+zZDKJY+%3~*p2h2t;SAMX*yEs4f0ki% z$lpN5VeE+@4U=w!aRxYcKe5*LV^72ZX`M${a~y_Q_6vuQw`JIl`bVKRHwH&WxM8>v zgMmh2#d6fnKw}OD8plor4EA9**z$^|z|u8m=iSddzsF zuP?(;akcf-vs3$p_}+XBIvaQO-F5oKGYj$m^@YGxS!FGErhc4M(Yhg)OV#}+zW4wA z*3U2Bln+f!jdP?#eu$l(_35^-$iKRVb7{X)`}g85xgvph)bc`tov!T~tr8IunIJzC_a4{V%yyHKzC??W_594HfOD zpIgJ^eeajQuq$Znt_oCW-;7fg=EUVG)d5+&OM7K`6l7|_`3h`ols8eFzWgI5J=R|9 zl=Y2MXI_J^oDEkrv?`f6+bdcm7VXbf|Cv)zO0nifimI&n_Q=VTj<#u-`_is%(eX2{ z+|U+l8mYEqeOz9?$~}|!Q!mKxlpgB&-r0w?y)(#~{&s$5nd$vdt@(GhY3kZL=0a9% zsx7v0)9-suobcW$kWq1cN0LNawVz*5)>hTpwx*!HW7+hyx1#gw>J2f~O%#i7Gfh=( zKja=~^zFlxo1rZ!_7_P%4lC6Dy|B90I7U@IBk0wkg=hVT7CMfNd~DAerMavzy~EHj g{^5u0JoKz3ES4`$O!vbX{+3vVA-G{;Vcuf>KPf(g^Z)<= literal 0 HcmV?d00001 diff --git a/misc/icons/Factor_128x128.png b/misc/icons/Factor_128x128.png new file mode 100644 index 0000000000000000000000000000000000000000..1854aa6f720d6427b13bfd8ab7bd9c5c90999fc5 GIT binary patch literal 21526 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 KMNUMnLSTYP>7#rA literal 0 HcmV?d00001 diff --git a/misc/icons/Factor_48x48.png b/misc/icons/Factor_48x48.png new file mode 100644 index 0000000000000000000000000000000000000000..364bb44d05610d6b6535fb1b0ee74c82726c485c GIT binary patch literal 4326 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 U;VZ~hXaE2J07*qoM6N<$g6o=EI{*Lx literal 0 HcmV?d00001 diff --git a/misc/icons/license.txt b/misc/icons/license.txt index 3a886d770c..7979a793a9 100644 --- a/misc/icons/license.txt +++ b/misc/icons/license.txt @@ -1,4 +1,4 @@ The icons/images/jackets contained in this archive are -Copyright (C) 2007 Elie CHAFTARI. All Rights Reserved. +Copyright (C) 2007 Elie Chaftari. All Rights Reserved. See http://factorcode.org/license.txt for BSD license. \ No newline at end of file diff --git a/vm/factor.rs b/vm/factor.rs index ffe83d00ab..5b983cacba 100644 --- a/vm/factor.rs +++ b/vm/factor.rs @@ -1,2 +1,2 @@ -fraptor ICON "misc/icons/FRaptorMix.ico" +fraptor ICON "misc/icons/Factor.ico" From 156581717593572d060686ee0eb88676dfba868d Mon Sep 17 00:00:00 2001 From: Sampo Vuori Date: Tue, 25 Sep 2007 20:30:27 +0300 Subject: [PATCH 04/21] Loading of cairo library added. More functionality. --- extra/cairo/cairo.factor | 144 ++++++++++++++++++++++++++++++++++----- 1 file changed, 128 insertions(+), 16 deletions(-) diff --git a/extra/cairo/cairo.factor b/extra/cairo/cairo.factor index 8cf79da9b4..5c4907e5bb 100644 --- a/extra/cairo/cairo.factor +++ b/extra/cairo/cairo.factor @@ -1,6 +1,25 @@ -! Cairo binding +! Bindings for Cairo library +! Copyright (c) 2007 Sampo Vuori +! License: http://factorcode.org/license.txt + +! Unimplemented: +! - most of the font stuff +! - most of the matrix stuff +! - most of the query functions + + +USING: alien alien.syntax combinators system ; + IN: cairo -USING: alien alien.syntax ; + +: load-cairo-library ( -- ) + "cairo" { + { [ win32? ] [ "cairo.dll" ] } + { [ macosx? ] [ "libcairo.dylib" ] } + { [ unix? ] [ "libcairo.so.2" ] } + } cond "cdecl" add-library ; parsing + +load-cairo-library ! cairo_status_t C-ENUM: @@ -10,24 +29,43 @@ C-ENUM: CAIRO_STATUS_INVALID_POP_GROUP CAIRO_STATUS_NO_CURRENT_POINT CAIRO_STATUS_INVALID_MATRIX - CAIRO_STATUS_NO_TARGET_SURFACE + CAIRO_STATUS_INVALID_STATUS CAIRO_STATUS_NULL_POINTER CAIRO_STATUS_INVALID_STRING + CAIRO_STATUS_INVALID_PATH_DATA + CAIRO_STATUS_READ_ERROR + CAIRO_STATUS_WRITE_ERROR + CAIRO_STATUS_SURFACE_FINISHED + CAIRO_STATUS_SURFACE_TYPE_MISMATCH + CAIRO_STATUS_PATTERN_TYPE_MISMATCH + CAIRO_STATUS_INVALID_CONTENT + CAIRO_STATUS_INVALID_FORMAT + CAIRO_STATUS_INVALID_VISUAL + CAIRO_STATUS_FILE_NOT_FOUND + CAIRO_STATUS_INVALID_DASH + CAIRO_STATUS_INVALID_DSC_COMMENT + CAIRO_STATUS_INVALID_INDEX + CAIRO_STATUS_CLIP_NOT_REPRESENTABLE ; +! cairo_content_t +: CAIRO_CONTENT_COLOR HEX: 1000 ; +: CAIRO_CONTENT_ALPHA HEX: 2000 ; +: CAIRO_CONTENT_COLOR_ALPHA HEX: 3000 ; + ! cairo_operator_t C-ENUM: CAIRO_OPERATOR_CLEAR - CAIRO_OPERATOR_SRC - CAIRO_OPERATOR_DST + CAIRO_OPERATOR_SOURCE CAIRO_OPERATOR_OVER - CAIRO_OPERATOR_OVER_REVERSE CAIRO_OPERATOR_IN - CAIRO_OPERATOR_IN_REVERSE CAIRO_OPERATOR_OUT - CAIRO_OPERATOR_OUT_REVERSE CAIRO_OPERATOR_ATOP - CAIRO_OPERATOR_ATOP_REVERSE + CAIRO_OPERATOR_DEST + CAIRO_OPERATOR_DEST_OVER + CAIRO_OPERATOR_DEST_IN + CAIRO_OPERATOR_DEST_OUT + CAIRO_OPERATOR_DEST_ATOP CAIRO_OPERATOR_XOR CAIRO_OPERATOR_ADD CAIRO_OPERATOR_SATURATE @@ -116,6 +154,14 @@ C-STRUCT: cairo_t { "cairo_gstate_t*" "gstate" } { "uint" "status ! cairo_status_t" } ; +C-STRUCT: cairo_matrix_t + { "double" "xx" } + { "double" "yx" } + { "double" "xy" } + { "double" "yy" } + { "double" "x0" } + { "double" "y0" } ; + ! cairo_format_t C-ENUM: CAIRO_FORMAT_ARGB32 @@ -160,15 +206,24 @@ C-ENUM: : cairo_create ( cairo_surface_t -- cairo_t ) "cairo_t*" "cairo" "cairo_create" [ "void*" ] alien-invoke ; +: cairo_reference ( cairo_t -- cairo_t ) + "cairo_t*" "cairo" "cairo_reference" [ "cairo_t*" ] alien-invoke ; + : cairo_destroy ( cairo_t -- ) "void" "cairo" "cairo_destroy" [ "cairo_t*" ] alien-invoke ; +: cairo_save ( cairo_t -- ) + "void" "cairo" "cairo_save" [ "cairo_t*" ] alien-invoke ; + +: cairo_restore ( cairo_t -- ) + "void" "cairo" "cairo_restore" [ "cairo_t*" ] alien-invoke ; + : cairo_set_operator ( cairo_t cairo_operator_t -- ) "void" "cairo" "cairo_set_operator" [ "cairo_t*" "int" ] alien-invoke ; -: cairo_image_surface_create_for_data ( data format width height stride -- cairo_surface_t ) - "void*" "cairo" "cairo_image_surface_create_for_data" [ "void*" "uint" "int" "int" "int" ] alien-invoke ; - +: cairo_set_source ( cairo_t cairo_pattern_t -- ) + "void" "cairo" "cairo_set_source" [ "cairo_t*" "void*" ] alien-invoke ; + : cairo_set_source_rgb ( cairo_t red green blue -- ) "void" "cairo" "cairo_set_source_rgb" [ "cairo_t*" "double" "double" "double" ] alien-invoke ; @@ -181,6 +236,10 @@ C-ENUM: : cairo_set_tolerance ( cairo_t tolerance -- ) "void" "cairo" "cairo_set_tolerance" [ "cairo_t*" "double" ] alien-invoke ; +: cairo_image_surface_create_for_data ( data format width height stride -- cairo_surface_t ) + "void*" "cairo" "cairo_image_surface_create_for_data" [ "void*" "uint" "int" "int" "int" ] alien-invoke ; + + : cairo_set_antialias ( cairo_t cairo_antialias_t -- ) "void" "cairo" "cairo_set_antialias" [ "cairo_t*" "int" ] alien-invoke ; @@ -211,6 +270,14 @@ C-ENUM: : cairo_rotate ( cairo_t angle -- ) "void" "cairo" "cairo_rotate" [ "cairo_t*" "double" ] alien-invoke ; +: cairo_transform ( cairo_t cairo_matrix_t -- ) + "void" "cairo" "cairo_transform" [ "cairo_t*" "cairo_matrix_t*" ] alien-invoke ; + +: cairo_set_matrix ( cairo_t cairo_matrix_t -- ) + "void" "cairo" "cairo_set_matrix" [ "cairo_t*" "cairo_matrix_t*" ] alien-invoke ; + +: cairo_identity_matrix ( cairo_t -- ) + "void" "cairo" "cairo_identity_matrix" [ "cairo_t*" ] alien-invoke ; ! cairo path creating functions @@ -219,6 +286,9 @@ C-ENUM: : cairo_move_to ( cairo_t x y -- ) "void" "cairo" "cairo_move_to" [ "cairo_t*" "double" "double" ] alien-invoke ; + +: cairo_new_sub_path ( cairo_t -- ) + "void" "cairo" "cairo_new_sub_path" [ "cairo_t*" ] alien-invoke ; : cairo_line_to ( cairo_t x y -- ) "void" "cairo" "cairo_line_to" [ "cairo_t*" "double" "double" ] alien-invoke ; @@ -247,6 +317,29 @@ C-ENUM: : cairo_close_path ( cairo_t -- ) "void" "cairo" "cairo_close_path" [ "cairo_t*" ] alien-invoke ; +! Surface manipulation + +: cairo_surface_create_similar ( cairo_surface_t cairo_content_t width height -- cairo_surface_t ) + "cairo_surface_t*" "cairo" "cairo_surface_create_similar" [ "cairo_surface_t*" "uint" "int" "int" ] alien-invoke ; + +: cairo_surface_reference ( cairo_surface_t -- cairo_surface_t ) + "cairo_surface_t*" "cairo" "cairo_surface_reference" [ "cairo_surface_t*" ] alien-invoke ; + +: cairo_surface_finish ( cairo_surface_t -- ) + "void" "cairo" "cairo_surface_finish" [ "cairo_surface_t*" ] alien-invoke ; + +: cairo_surface_destroy ( cairo_surface_t -- ) + "void" "cairo" "cairo_surface_destroy" [ "cairo_surface_t*" ] alien-invoke ; + +: cairo_surface_get_reference_count ( cairo_surface_t -- count ) + "uint" "cairo" "cairo_surface_get_reference_count" [ "cairo_surface_t*" ] alien-invoke ; + +: cairo_surface_status ( cairo_surface_t -- cairo_status_t ) + "uint" "cairo" "cairo_surface_status" [ "cairo_surface_t*" ] alien-invoke ; + +: cairo_surface_flush ( cairo_surface_t -- ) + "void" "cairo" "cairo_surface_flush" [ "cairo_surface_t*" ] alien-invoke ; + ! painting functions : cairo_paint ( cairo_t -- ) "void" "cairo" "cairo_paint" [ "cairo_t*" ] alien-invoke ; @@ -302,8 +395,6 @@ C-ENUM: : cairo_clip_preserve ( cairo_t -- ) "void" "cairo" "cairo_clip_preserve" [ "cairo_t*" ] alien-invoke ; -: cairo_set_source ( cairo_t cairo_pattern_t -- ) - "void" "cairo" "cairo_set_source" [ "cairo_t*" "void*" ] alien-invoke ; : cairo_pattern_create_linear ( x0 y0 x1 y1 -- cairo_pattern_t ) "void*" "cairo" "cairo_pattern_create_linear" [ "double" "double" "double" "double" ] alien-invoke ; @@ -326,5 +417,26 @@ C-ENUM: : cairo_set_font_size ( cairo_t scale -- ) "void" "cairo" "cairo_set_font_size" [ "cairo_t*" "double" ] alien-invoke ; -: cairo_identity_matrix ( cairo_t -- ) - "void" "cairo" "cairo_identity_matrix" [ "cairo_t*" ] alien-invoke ; +: cairo_set_font_matrix ( cairo_t cairo_matrix_t -- ) + "void" "cairo" "cairo_set_font_matrix" [ "cairo_t*" "cairo_matrix_t*" ] alien-invoke ; + +: cairo_get_font_matrix ( cairo_t cairo_matrix_t -- ) + "void" "cairo" "cairo_get_font_matrix" [ "cairo_t*" "cairo_matrix_t*" ] alien-invoke ; + + + +! Cairo pdf + +: cairo_pdf_surface_create ( filename width height -- surface ) + "void*" "cairo" "cairo_pdf_surface_create" [ "char*" "double" "double" ] alien-invoke ; + +! Missing: + +! cairo_public cairo_surface_t * +! cairo_pdf_surface_create_for_stream (cairo_write_func_t write_func, +! void *closure, +! double width_in_points, +! double height_in_points); + +: cairo_pdf_surface_set_size ( surface width height -- ) + "void" "cairo" "cairo_pdf_surface_set_size" [ "void*" "double" "double" ] alien-invoke ; From 3a3eeb282447ce37b890c936da98be86bae11c28 Mon Sep 17 00:00:00 2001 From: Sampo Vuori Date: Tue, 25 Sep 2007 22:06:28 +0300 Subject: [PATCH 05/21] Added a new cairo demo --- extra/cairo-demo/cairo-demo.factor | 72 ++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 extra/cairo-demo/cairo-demo.factor diff --git a/extra/cairo-demo/cairo-demo.factor b/extra/cairo-demo/cairo-demo.factor new file mode 100644 index 0000000000..9d7af090a7 --- /dev/null +++ b/extra/cairo-demo/cairo-demo.factor @@ -0,0 +1,72 @@ +! Cairo "Hello World" demo +! Copyright (c) 2007 Sampo Vuori +! License: http://factorcode.org/license.txt +! +! This example is an adaptation of the following cairo sample code: +! http://cairographics.org/samples/text/ + + +USING: cairo math math.constants byte-arrays kernel ui ui.render + ui.gadgets opengl.gl ; + +IN: cairo-demo + + +: make-image-array ( -- array ) + 384 256 4 * * ; + +: convert-array-to-surface ( array -- cairo_surface_t ) + CAIRO_FORMAT_ARGB32 384 256 over 4 * + cairo_image_surface_create_for_data ; + + +TUPLE: cairo-gadget image-array cairo-t ; + +M: cairo-gadget draw-gadget* ( gadget -- ) + 0 0 glRasterPos2i + 1.0 -1.0 glPixelZoom + >r 384 256 GL_RGBA GL_UNSIGNED_BYTE r> + cairo-gadget-image-array glDrawPixels ; + +: create-surface ( gadget -- cairo_surface_t ) + make-image-array dup >r swap set-cairo-gadget-image-array r> convert-array-to-surface ; + +: init-cairo ( gadget -- cairo_t ) + create-surface cairo_create ; + +M: cairo-gadget pref-dim* drop { 384 256 0 } ; + +: draw-hello-world ( gadget -- ) + cairo-gadget-cairo-t + dup "Sans" CAIRO_FONT_SLANT_NORMAL CAIRO_FONT_WEIGHT_BOLD cairo_select_font_face + dup 90.0 cairo_set_font_size + dup 10.0 135.0 cairo_move_to + dup "Hello" cairo_show_text + dup 70.0 165.0 cairo_move_to + dup "World" cairo_text_path + dup 0.5 0.5 1 cairo_set_source_rgb + dup cairo_fill_preserve + dup 0 0 0 cairo_set_source_rgb + dup 2.56 cairo_set_line_width + dup cairo_stroke + dup 1 0.2 0.2 0.6 cairo_set_source_rgba + dup 10.0 135.0 5.12 0 pi 2 * cairo_arc + dup cairo_close_path + dup 70.0 165.0 5.12 0 pi 2 * cairo_arc + cairo_fill ; + +M: cairo-gadget graft* ( gadget -- ) + dup dup init-cairo swap set-cairo-gadget-cairo-t draw-hello-world ; + +M: cairo-gadget ungraft* ( gadget -- ) + cairo-gadget-cairo-t cairo_destroy ; + +: ( -- gadget ) + cairo-gadget construct-gadget ; + +: run ( -- ) + [ + "Hello World from Factor!" open-window + ] with-ui ; + +MAIN: run From e0318f769d720c87975446f184e599d9a971a1b6 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Tue, 25 Sep 2007 20:30:33 -0400 Subject: [PATCH 06/21] Updating HTML output for latest stream protocol --- extra/html/elements/elements.factor | 2 +- extra/html/html-tests.factor | 65 +- extra/html/html.factor | 218 +- .../server/resources => html}/stylesheet.css | 0 extra/http/server/resources/prototype.js | 1781 ----------------- 5 files changed, 159 insertions(+), 1907 deletions(-) rename extra/{http/server/resources => html}/stylesheet.css (100%) delete mode 100644 extra/http/server/resources/prototype.js diff --git a/extra/html/elements/elements.factor b/extra/html/elements/elements.factor index 09ef3a4c03..0b70f5aa5c 100644 --- a/extra/html/elements/elements.factor +++ b/extra/html/elements/elements.factor @@ -152,5 +152,5 @@ SYMBOL: html "size" "href" "class" "border" "rows" "cols" "id" "onclick" "style" "valign" "accesskey" "src" "language" "colspan" "onchange" "rel" - "width" "selected" "onsubmit" + "width" "selected" "onsubmit" "xmlns" "lang" "xml:lang" ] [ define-attribute-word ] each diff --git a/extra/html/html-tests.factor b/extra/html/html-tests.factor index 5beb81b29a..798d5563fe 100644 --- a/extra/html/html-tests.factor +++ b/extra/html/html-tests.factor @@ -1,30 +1,39 @@ USING: html http io io.streams.string io.styles kernel -namespaces tools.test xml.writer ; +namespaces tools.test xml.writer sbufs sequences html.private ; IN: temporary -[ - "/responder/foo?z=%20" -] [ - "/responder/foo" H{ { "z" " " } } build-url +: make-html-string + [ with-html-stream ] string-out ; + +[ ] [ + 512 drop ] unit-test -[ - "<html>&'sgml'" -] [ "&'sgml'" chars>entities ] unit-test +[ "" ] [ + [ "" write ] make-html-string +] unit-test -[ "" ] -[ +[ "a" ] [ + [ CHAR: a write1 ] make-html-string +] unit-test + +[ "<" ] [ + [ "<" write ] make-html-string +] unit-test + +[ "<" ] [ + [ "<" H{ } stdio get format-html-span ] make-html-string +] unit-test + +TUPLE: funky town ; + +M: funky browser-link-href + "http://www.funky-town.com/" swap funky-town append ; + +[ "<" ] [ [ - H{ } [ drop ] span-tag - ] string-out -] unit-test - -: html-format ( string style -- string ) - [ format ] with-html-stream ; - -[ "hello world" ] -[ - [ "hello world" H{ } html-format ] string-out + "<" "austin" funky construct-boa write-object + ] make-html-string ] unit-test [ "car" ] @@ -32,8 +41,8 @@ IN: temporary [ "car" H{ { font "monospace" } } - html-format - ] string-out + format + ] make-html-string ] unit-test [ "car" ] @@ -41,6 +50,14 @@ IN: temporary [ "car" H{ { foreground { 1 0 1 1 } } } - html-format - ] string-out + format + ] make-html-string +] unit-test + +[ "

- ] html-document + ] simple-html-document ] show-final ; : counter-example ( count -- ) @@ -87,7 +87,7 @@ IN: http.server.responders.continuation.examples "++" over 1quotation [ f ] swap append [ 1 + counter-example ] append quot-href "--" over 1quotation [ f ] swap append [ 1 - counter-example ] append quot-href drop - ] html-document + ] simple-html-document ] show drop ; : counter-example2 ( -- ) @@ -102,7 +102,7 @@ IN: http.server.responders.continuation.examples

"counter" get unparse write

"++" [ "counter" get 1 + "counter" set ] quot-href "--" [ "counter" get 1 - "counter" set ] quot-href - ] html-document + ] simple-html-document ] show drop ; diff --git a/extra/http/server/responders/file/file.factor b/extra/http/server/responders/file/file.factor index e6af805462..4f83e8fa98 100644 --- a/extra/http/server/responders/file/file.factor +++ b/extra/http/server/responders/file/file.factor @@ -1,8 +1,9 @@ ! Copyright (C) 2004, 2006 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. -USING: calendar html io io.files kernel math math.parser http.server.responders -http.server.templating namespaces parser sequences strings assocs hashtables -debugger http.mime sorting ; +USING: calendar html io io.files kernel math math.parser +http.server.responders http.server.templating namespaces parser +sequences strings assocs hashtables debugger http.mime sorting +html.elements ; IN: http.server.responders.file @@ -55,19 +56,25 @@ SYMBOL: page dup mime-type dup "application/x-factor-server-page" = [ drop serving-html run-page ] [ serve-static ] if ; -: file. ( path name dirp -- ) - "[DIR] " " " ? write - dup write-object nl ; +: file. ( name dirp -- ) + [ "/" append ] when + dup write ; -: directory. ( path -- ) - directory sort-keys [ first2 file. ] each ; +: directory. ( path request -- ) + dup [ +

write

+
    + directory sort-keys + [
  • file.
  • ] assoc-each +
+ ] simple-html-document ; : list-directory ( directory -- ) serving-html "method" get "head" = [ drop ] [ - "request" get [ directory. ] simple-html-document + "request" get directory. ] if ; : find-index ( filename -- path ) @@ -98,17 +105,17 @@ SYMBOL: page ] if ; global [ - ! Javascript source used by ajax libraries + ! Serve up our own source code "resources" [ [ - "extra/http/server/resources/" resource-path "doc-root" set + "" resource-path "doc-root" set file-responder ] with-scope ] add-simple-responder ! Serves files from a directory stored in the "doc-root" - ! variable. You can set the variable in the global namespace, - ! or inside the responder. + ! variable. You can set the variable in the global + ! namespace, or inside the responder. "file" [ file-responder ] add-simple-responder ! The root directory is served by... diff --git a/extra/http/server/responders/responders.factor b/extra/http/server/responders/responders.factor index 725cb515b0..aadf513aea 100644 --- a/extra/http/server/responders/responders.factor +++ b/extra/http/server/responders/responders.factor @@ -16,16 +16,16 @@ SYMBOL: responders : response ( header msg -- ) "HTTP/1.0 " write print print-header ; -: error-body ( error -- body ) +: error-body ( error -- )

write

; : error-head ( error -- ) dup log-error - H{ { "Content-Type" "text/html" } } over response ; + H{ { "Content-Type" "text/html" } } swap response ; : httpd-error ( error -- ) #! This must be run from handle-request - error-head + dup error-head "head" "method" get = [ drop ] [ nl error-body ] if ; : bad-request ( -- ) @@ -101,7 +101,8 @@ SYMBOL: max-post-request dup "request" set ; : prepare-header ( -- ) - read-header dup "header" set + read-header + dup "header" set dup log-headers read-post-request "response" set "raw-response" set ; diff --git a/extra/webapps/help/help.factor b/extra/webapps/help/help.factor index ec0590df34..366baffcb9 100644 --- a/extra/webapps/help/help.factor +++ b/extra/webapps/help/help.factor @@ -10,7 +10,7 @@ IN: webapps.help serving-html dup article-title [ [ help ] with-html-stream - ] html-document ; + ] simple-html-document ; : string>topic ( string -- topic ) " " split dup length 1 = [ first ] when ; @@ -73,9 +73,10 @@ M: vocab-author browser-link-href "help" "show-help" "extra/webapps/help" web-app ! Hard-coding for factorcode.org -M: pathname browser-link-href - pathname-string "resource:" ?head [ - "http://factorcode.org/repos/Factor/" swap append - ] [ - drop f - ] if ; +PREDICATE: pathname resource-pathname + pathname-string "resource:" head? ; + +M: resource-pathname browser-link-href + pathname-string + "resource:" ?head drop + "/responder/resources/" swap append ; From 6529e170677b9255186a334c49db601827c3967f Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Tue, 25 Sep 2007 20:31:45 -0400 Subject: [PATCH 09/21] Fix PowerPC callstack traces --- vm/stack.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/vm/stack.c b/vm/stack.c index cf3c1df00a..b2a05b9181 100644 --- a/vm/stack.c +++ b/vm/stack.c @@ -407,13 +407,12 @@ void stack_frame_to_array(F_STACK_FRAME *frame) offset = F; #ifdef CALLSTACK_UP_P - #define I(n) (n) + set_array_nth(array,frame_index++,frame_executing(frame)); + set_array_nth(array,frame_index++,offset); #else - #define I(n) (array_capacity(array) - (n) - 1) + set_array_nth(array,frame_index--,offset); + set_array_nth(array,frame_index--,frame_executing(frame)); #endif - - set_array_nth(array,I(frame_index++),frame_executing(frame)); - set_array_nth(array,I(frame_index++),offset); } DEFINE_PRIMITIVE(callstack_to_array) @@ -429,7 +428,12 @@ DEFINE_PRIMITIVE(callstack_to_array) /* frame_count is equal to the total length now */ +#ifdef CALLSTACK_UP_P frame_index = 0; +#else + frame_index = frame_count - 1; +#endif + iterate_callstack_object(stack,stack_frame_to_array); dpush(tag_object(array)); From a26d912bd762c3dc1a6e8cb7a7c7f4c8860832ce Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Tue, 25 Sep 2007 20:54:05 -0400 Subject: [PATCH 10/21] Updating extra/ modules --- core/optimizer/debugger/debugger.factor | 2 +- extra/benchmark/dispatch4/dispatch4.factor | 3 ++- extra/channels/sniffer/bsd/bsd.factor | 2 +- extra/cpu/8080/8080.factor | 3 ++- extra/icfp/2006/2006.factor | 3 ++- extra/io/sniffer/filter/bsd/bsd.factor | 2 +- extra/io/streams/null/null.factor | 5 ++++- extra/locals/locals.factor | 3 ++- extra/openal/macosx/macosx.factor | 3 ++- extra/space-invaders/space-invaders.factor | 3 ++- extra/state-machine/state-machine.factor | 4 ++-- 11 files changed, 21 insertions(+), 12 deletions(-) diff --git a/core/optimizer/debugger/debugger.factor b/core/optimizer/debugger/debugger.factor index 6c323fce1e..ed0358fe7f 100644 --- a/core/optimizer/debugger/debugger.factor +++ b/core/optimizer/debugger/debugger.factor @@ -3,7 +3,7 @@ USING: classes inference inference.dataflow io kernel kernel.private math.parser namespaces optimizer prettyprint prettyprint.backend sequences words arrays match macros -assocs ; +assocs combinators.private ; IN: optimizer.debugger ! A simple tool for turning dataflow IR into quotations, for diff --git a/extra/benchmark/dispatch4/dispatch4.factor b/extra/benchmark/dispatch4/dispatch4.factor index 3ad41337d5..a5bb983151 100644 --- a/extra/benchmark/dispatch4/dispatch4.factor +++ b/extra/benchmark/dispatch4/dispatch4.factor @@ -1,4 +1,5 @@ -USING: kernel.private kernel sequences math combinators ; +USING: kernel.private kernel sequences math combinators +combinators.private ; IN: benchmark.dispatch4 : foobar-1 diff --git a/extra/channels/sniffer/bsd/bsd.factor b/extra/channels/sniffer/bsd/bsd.factor index dd72279e4b..ba8e5ceeb9 100644 --- a/extra/channels/sniffer/bsd/bsd.factor +++ b/extra/channels/sniffer/bsd/bsd.factor @@ -3,7 +3,7 @@ ! ! Wrap a sniffer in a channel USING: kernel channels channels.sniffer concurrency io -io.sniffer io.sniffer.bsd ; +io.sniffer io.sniffer.bsd io.unix.backend ; M: unix-io sniff-channel ( -- channel ) "/dev/bpf0" "en1" [ diff --git a/extra/cpu/8080/8080.factor b/extra/cpu/8080/8080.factor index 34666b3288..87c3a235fd 100644 --- a/extra/cpu/8080/8080.factor +++ b/extra/cpu/8080/8080.factor @@ -3,7 +3,8 @@ ! USING: kernel math sequences words arrays io io.files namespaces math.parser kernel.private - assocs quotations parser parser-combinators tools.time ; + assocs quotations parser parser-combinators tools.time + combinators.private ; IN: cpu.8080 TUPLE: cpu b c d e f h l a pc sp halted? last-interrupt cycles ram ; diff --git a/extra/icfp/2006/2006.factor b/extra/icfp/2006/2006.factor index 317a5ae83b..2b42cddc6a 100644 --- a/extra/icfp/2006/2006.factor +++ b/extra/icfp/2006/2006.factor @@ -2,7 +2,8 @@ ! See http://factorcode.org/license.txt for BSD license. USING: kernel math sequences kernel.private namespaces arrays -io io.files splitting io.binary math.functions vectors ; +io io.files splitting io.binary math.functions vectors +quotations combinators.private ; IN: universal-machine SYMBOL: regs diff --git a/extra/io/sniffer/filter/bsd/bsd.factor b/extra/io/sniffer/filter/bsd/bsd.factor index c986a09664..fc34b3448b 100644 --- a/extra/io/sniffer/filter/bsd/bsd.factor +++ b/extra/io/sniffer/filter/bsd/bsd.factor @@ -1,7 +1,7 @@ USING: alien.c-types hexdump io io.backend io.sockets.headers io.sockets.headers.bsd kernel io.sniffer io.sniffer.bsd io.sniffer.filter io.streams.string io.unix.backend math -sequences system ; +sequences system byte-arrays ; IN: io.sniffer.filter.bsd ! http://www.iana.org/assignments/ethernet-numbers diff --git a/extra/io/streams/null/null.factor b/extra/io/streams/null/null.factor index 7c11130397..12a36091ce 100644 --- a/extra/io/streams/null/null.factor +++ b/extra/io/streams/null/null.factor @@ -16,7 +16,10 @@ M: null-stream stream-write 2drop ; M: null-stream stream-nl drop ; M: null-stream stream-flush drop ; M: null-stream stream-format 3drop ; -M: null-stream with-nested-stream rot drop with-stream* ; +M: null-stream make-span-stream nip ; +M: null-stream make-block-stream nip ; +M: null-stream make-cell-stream nip ; +M: null-stream stream-write-table 3drop ; : with-null-stream ( quot -- ) T{ null-stream } swap with-stream* ; inline diff --git a/extra/locals/locals.factor b/extra/locals/locals.factor index ca157fa2a7..688507be78 100644 --- a/extra/locals/locals.factor +++ b/extra/locals/locals.factor @@ -4,7 +4,8 @@ USING: kernel namespaces sequences sequences.private assocs math inference.transforms parser words quotations debugger macros arrays macros splitting combinators prettyprint.backend - definitions prettyprint hashtables combinators.lib ; + definitions prettyprint hashtables combinators.lib + prettyprint.sections ; IN: locals diff --git a/extra/openal/macosx/macosx.factor b/extra/openal/macosx/macosx.factor index 21c918e33e..77484aca74 100644 --- a/extra/openal/macosx/macosx.factor +++ b/extra/openal/macosx/macosx.factor @@ -2,7 +2,8 @@ ! See http://factorcode.org/license.txt for BSD license. ! IN: openal.macosx -USING: openal alien.c-types kernel alien alien.syntax shuffle ; +USING: openal alien.c-types kernel alien alien.syntax shuffle +combinators.lib ; LIBRARY: alut diff --git a/extra/space-invaders/space-invaders.factor b/extra/space-invaders/space-invaders.factor index 287e6eebb8..3f695a4f60 100644 --- a/extra/space-invaders/space-invaders.factor +++ b/extra/space-invaders/space-invaders.factor @@ -4,7 +4,8 @@ USING: cpu.8080 openal math alien.c-types sequences kernel shuffle arrays io.files combinators kernel.private ui.gestures ui.gadgets ui.render opengl.gl system - threads concurrency match ui byte-arrays combinators.lib ; + threads concurrency match ui byte-arrays combinators.lib + combinators.private ; IN: space-invaders TUPLE: space-invaders port1 port2i port2o port3o port4lo port4hi port5o bitmap sounds looping? ; diff --git a/extra/state-machine/state-machine.factor b/extra/state-machine/state-machine.factor index 671150b10a..85f4812d9a 100644 --- a/extra/state-machine/state-machine.factor +++ b/extra/state-machine/state-machine.factor @@ -1,5 +1,5 @@ -USING: kernel parser strings math namespaces sequences words io arrays -quotations debugger kernel.private ; +USING: kernel parser strings math namespaces sequences words io +arrays quotations debugger kernel.private combinators.private ; IN: state-machine : STATES: From 1e676eb2b9af7d0a6891cd40c18fcfc9f776726e Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Tue, 25 Sep 2007 21:09:46 -0400 Subject: [PATCH 11/21] Change check-slice --- core/sequences/sequences.factor | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/core/sequences/sequences.factor b/core/sequences/sequences.factor index 8d883ddcbb..1a8e5c9561 100644 --- a/core/sequences/sequences.factor +++ b/core/sequences/sequences.factor @@ -191,14 +191,14 @@ TUPLE: slice from to seq ; TUPLE: slice-error reason ; : slice-error ( str -- * ) \ slice-error construct-boa throw ; -: check-slice ( from to seq -- ) +: check-slice ( from to seq -- from to seq ) pick 0 < [ "start < 0" slice-error ] when - length over < [ "end > sequence" slice-error ] when - > [ "start > end" slice-error ] when ; + dup length pick < [ "end > sequence" slice-error ] when + pick pick > [ "start > end" slice-error ] when ; : ( from to seq -- slice ) dup slice? [ collapse-slice ] when - 3dup check-slice + check-slice slice construct-boa ; M: slice virtual-seq slice-seq ; @@ -259,7 +259,7 @@ INSTANCE: repetition immutable-sequence PRIVATE> : subseq ( from to seq -- subseq ) - [ 3dup check-slice prepare-subseq (copy) ] keep like ; + [ check-slice prepare-subseq (copy) ] keep like ; : head ( seq n -- headseq ) (head) subseq ; @@ -525,7 +525,7 @@ M: sequence <=> ] if ; : delete-slice ( from to seq -- ) - 3dup check-slice >r over >r - r> r> open-slice ; + check-slice >r over >r - r> r> open-slice ; : delete-nth ( n seq -- ) >r dup 1+ r> delete-slice ; From 0c6865a10b5c149fc29d3c0e1a2516e8f3fe6453 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Tue, 25 Sep 2007 21:23:20 -0400 Subject: [PATCH 12/21] Lazy JIT --- vm/cpu-ppc.S | 27 +++++++++++++++++++++------ vm/cpu-ppc.h | 1 + vm/data_gc.c | 2 +- vm/image.c | 7 +++---- vm/jit.c | 15 --------------- vm/jit.h | 4 ++-- vm/types.c | 7 +------ 7 files changed, 29 insertions(+), 34 deletions(-) diff --git a/vm/cpu-ppc.S b/vm/cpu-ppc.S index 295e16f04c..b1f8298eb0 100644 --- a/vm/cpu-ppc.S +++ b/vm/cpu-ppc.S @@ -40,11 +40,19 @@ in the public domain. */ #define RESTORE(register,offset) lwz register,SAVE_AT(offset)(r1) -DEF(void,c_to_factor,(CELL quot)): - mflr r0 /* get caller's return address */ - stwu r1,-FRAME(r1) /* create a stack frame to hold non-volatile registers */ +#define PROLOGUE \ + mflr r0 ; /* get caller's return address */ \ + stwu r1,-FRAME(r1) ; /* create a stack frame to hold non-volatile registers */ SAVE_LR(r0) +#define EPILOGUE \ + LOAD_LR(r0) ; \ + lwz r1,0(r1) ; /* destroy the stack frame */ \ + mtlr r0 /* get ready to return */ \ + +DEF(void,c_to_factor,(CELL quot)): + PROLOGUE + SAVE(r13,0) /* save GPRs */ /* don't save ds pointer */ /* don't save rs pointer */ @@ -92,9 +100,7 @@ DEF(void,c_to_factor,(CELL quot)): /* don't restore ds pointer */ RESTORE(r13,0) - LOAD_LR(r0) - lwz r1,0(r1) /* destroy the stack frame */ - mtlr r0 /* get ready to return */ + EPILOGUE blr /* The JIT compiles an 'mr r4,r1' in front of every primitive call, since a @@ -164,6 +170,15 @@ DEF(void,throw_impl,(CELL quot, F_STACK_FRAME *rewind_to)): mtlr r0 JUMP_QUOT /* call the quotation */ +DEF(void,lazy_jit_compile,(CELL quot)): + mr r4,r1 /* save stack pointer */ + PROLOGUE + SAVE(r3,19) /* save quotation since we're about to mangle it */ + b MANGLE(jit_compile) + RESTORE(r3,19) /* restore quotation */ + EPILOGUE + JUMP_QUOT /* call the quotation */ + /* Thanks to Joshua Grams for this code. On PowerPC processors, we must flush the instruction cache manually diff --git a/vm/cpu-ppc.h b/vm/cpu-ppc.h index e4ff35c15c..c74e13e68b 100644 --- a/vm/cpu-ppc.h +++ b/vm/cpu-ppc.h @@ -11,6 +11,7 @@ void docol(CELL word); void undefined(CELL word); void set_callstack(F_STACK_FRAME *to, F_STACK_FRAME *from, CELL length, void *memcpy); void throw_impl(CELL quot, F_STACK_FRAME *rewind); +void lazy_jit_compile(CELL quot); void flush_icache(CELL start, CELL len); #define FRAME_SUCCESSOR(frame) (frame)->previous diff --git a/vm/data_gc.c b/vm/data_gc.c index eaf88f31c5..a94dcadf81 100644 --- a/vm/data_gc.c +++ b/vm/data_gc.c @@ -553,7 +553,7 @@ CELL collect_next(CELL scan) break; case QUOTATION_TYPE: quot = (F_QUOTATION *)scan; - if(collecting_code && quot->xt != NULL) + if(collecting_code && quot->xt != lazy_jit_compile) recursive_mark(quot->xt); break; case CALLSTACK_TYPE: diff --git a/vm/image.c b/vm/image.c index 32e628f902..d0f4635f82 100644 --- a/vm/image.c +++ b/vm/image.c @@ -162,10 +162,9 @@ void fixup_word(F_WORD *word) void fixup_quotation(F_QUOTATION *quot) { - /* quot->xt is only ever NULL at the start of stage2 bootstrap, - in this case the JIT compiles all quotations */ - if(quot->xt) - code_fixup("->xt); + code_fixup("->xt); + if(!in_code_heap_p(quot->xt)) + quot->xt = lazy_jit_compile; } void fixup_alien(F_ALIEN *d) diff --git a/vm/jit.c b/vm/jit.c index 7cdd645683..c6904414b5 100644 --- a/vm/jit.c +++ b/vm/jit.c @@ -152,21 +152,6 @@ void jit_compile(F_QUOTATION *quot) quot->xt = xt; } -void jit_compile_all(void) -{ - begin_scan(); - - CELL obj; - while((obj = next_object()) != F) - { - if(type_of(obj) == QUOTATION_TYPE) - jit_compile(untag_quotation(obj)); - } - - /* End the scan */ - gc_off = false; -} - XT quot_offset_to_pc(F_QUOTATION *quot, F_FIXNUM offset) { if(offset != -1) diff --git a/vm/jit.h b/vm/jit.h index 1758a24ff1..b3a54d604f 100644 --- a/vm/jit.h +++ b/vm/jit.h @@ -1,3 +1,3 @@ -void jit_compile(F_QUOTATION *quot); -void jit_compile_all(void); +DLLEXPORT void jit_compile(F_QUOTATION *quot); +jit_compile_all(void); XT quot_offset_to_pc(F_QUOTATION *quot, F_FIXNUM offset); diff --git a/vm/types.c b/vm/types.c index 1b9b3513dc..a17999a98b 100644 --- a/vm/types.c +++ b/vm/types.c @@ -131,12 +131,7 @@ DEFINE_PRIMITIVE(array_to_quotation) { F_QUOTATION *quot = allot_object(QUOTATION_TYPE,sizeof(F_QUOTATION)); quot->array = dpeek(); - quot->xt = NULL; - - REGISTER_UNTAGGED(quot); - jit_compile(quot); - UNREGISTER_UNTAGGED(quot); - + quot->xt = lazy_jit_compile; drepl(tag_object(quot)); } From f400729792957fcf479d0905f94673317e95066a Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Wed, 26 Sep 2007 00:26:19 -0400 Subject: [PATCH 13/21] The JIT now compiles quotations when first invoked, not when constructed --- core/bootstrap/image/image.factor | 3 ++- core/bootstrap/primitives.factor | 7 +++++++ vm/cpu-ppc.S | 18 +++++++++--------- vm/debug.c | 13 +++++++++++-- vm/factor.c | 8 -------- vm/image.c | 11 ++++++----- vm/jit.c | 6 +++++- vm/jit.h | 3 +-- vm/layouts.h | 2 ++ vm/run.c | 14 ++++++-------- vm/run.h | 2 +- vm/types.c | 8 ++++++-- 12 files changed, 56 insertions(+), 39 deletions(-) diff --git a/core/bootstrap/image/image.factor b/core/bootstrap/image/image.factor index 0f61eb4c83..c749ec3dad 100644 --- a/core/bootstrap/image/image.factor +++ b/core/bootstrap/image/image.factor @@ -36,7 +36,7 @@ IN: bootstrap.image : wrapper@ bootstrap-cell object tag-number - ; : word-xt@ 8 bootstrap-cells object tag-number - ; : quot-array@ bootstrap-cell object tag-number - ; -: quot-xt@ 2 bootstrap-cells object tag-number - ; +: quot-xt@ 3 bootstrap-cells object tag-number - ; ! The image being constructed; a vector of word-size integers SYMBOL: image @@ -312,6 +312,7 @@ M: quotation ' quotation-array ' quotation type-number object tag-number [ emit ! array + f ' emit ! compiled? 0 emit ! XT ] emit-object ] cache ; diff --git a/core/bootstrap/primitives.factor b/core/bootstrap/primitives.factor index 5e7bc1f338..edd1d42dcf 100644 --- a/core/bootstrap/primitives.factor +++ b/core/bootstrap/primitives.factor @@ -452,6 +452,13 @@ num-types get f builtins set { "quotation-array" "quotations.private" } f } + { + { "object" "kernel" } + "compiled?" + 2 + { "quotation-compiled?" "quotations" } + f + } } define-builtin "dll" "alien" create "dll?" "alien" create diff --git a/vm/cpu-ppc.S b/vm/cpu-ppc.S index b1f8298eb0..ba539c1fdc 100644 --- a/vm/cpu-ppc.S +++ b/vm/cpu-ppc.S @@ -4,7 +4,7 @@ in the public domain. */ /* Note that the XT is passed to the quotation in r11 */ #define CALL_OR_JUMP_QUOT \ - lwz r11,5(r3) /* load quotation-xt slot */ XX \ + lwz r11,9(r3) /* load quotation-xt slot */ XX \ #define CALL_QUOT \ CALL_OR_JUMP_QUOT XX \ @@ -41,14 +41,14 @@ in the public domain. */ #define RESTORE(register,offset) lwz register,SAVE_AT(offset)(r1) #define PROLOGUE \ - mflr r0 ; /* get caller's return address */ \ - stwu r1,-FRAME(r1) ; /* create a stack frame to hold non-volatile registers */ + mflr r0 XX /* get caller's return address */ \ + stwu r1,-FRAME(r1) XX /* create a stack frame to hold non-volatile registers */ \ SAVE_LR(r0) #define EPILOGUE \ - LOAD_LR(r0) ; \ - lwz r1,0(r1) ; /* destroy the stack frame */ \ - mtlr r0 /* get ready to return */ \ + LOAD_LR(r0) XX \ + lwz r1,0(r1) XX /* destroy the stack frame */ \ + mtlr r0 /* get ready to return */ DEF(void,c_to_factor,(CELL quot)): PROLOGUE @@ -173,9 +173,9 @@ DEF(void,throw_impl,(CELL quot, F_STACK_FRAME *rewind_to)): DEF(void,lazy_jit_compile,(CELL quot)): mr r4,r1 /* save stack pointer */ PROLOGUE - SAVE(r3,19) /* save quotation since we're about to mangle it */ - b MANGLE(jit_compile) - RESTORE(r3,19) /* restore quotation */ + SAVE(r3,18) /* save quot */ + bl MANGLE(jit_compile) + RESTORE(r3,18) EPILOGUE JUMP_QUOT /* call the quotation */ diff --git a/vm/debug.c b/vm/debug.c index b7fb4ff68f..57d195e2ba 100644 --- a/vm/debug.c +++ b/vm/debug.c @@ -3,7 +3,12 @@ void print_word(F_WORD* word, CELL nesting) { if(type_of(word->name) == STRING_TYPE) - printf("%s",to_char_string(untag_string(word->name),true)); + { + F_STRING *string = untag_string(word->name); + CELL i; + for(i = 0; i < string_capacity(string); i++) + putchar(cget(SREF(string,i))); + } else { printf("#xt) - { - /* This can only happen when we're starting a stage2 bootstrap. - The stage1 bootstrapper doesn't attempt to compile quotations, - so we do it here. */ - jit_compile_all(); - } - nest_stacks(); c_to_factor_toplevel(userenv[BOOT_ENV]); unnest_stacks(); diff --git a/vm/image.c b/vm/image.c index d0f4635f82..a4fd08af00 100644 --- a/vm/image.c +++ b/vm/image.c @@ -154,17 +154,18 @@ void fixup_word(F_WORD *word) { /* If this is a compiled word, relocate the code pointer. Otherwise, reset it based on the primitive number of the word. */ - if(word->compiledp != F) - code_fixup(&word->xt); + if(word->compiledp == F) + word->xt = default_word_xt(word); else - update_xt(word); + code_fixup(&word->xt); } void fixup_quotation(F_QUOTATION *quot) { - code_fixup("->xt); - if(!in_code_heap_p(quot->xt)) + if(quot->compiled == F) quot->xt = lazy_jit_compile; + else + code_fixup("->xt); } void fixup_alien(F_ALIEN *d) diff --git a/vm/jit.c b/vm/jit.c index c6904414b5..d10f25c325 100644 --- a/vm/jit.c +++ b/vm/jit.c @@ -34,8 +34,11 @@ bool jit_stack_frame_p(F_ARRAY *array) return false; } -void jit_compile(F_QUOTATION *quot) +FASTCALL void jit_compile(CELL tagged, F_STACK_FRAME *stack) { + stack_chain->callstack_top = stack; + + F_QUOTATION *quot = untag_quotation(tagged); F_ARRAY *array = untag_object(quot->array); REGISTER_UNTAGGED(quot); @@ -150,6 +153,7 @@ void jit_compile(F_QUOTATION *quot) UNREGISTER_UNTAGGED(quot); quot->xt = xt; + quot->compiled = T; } XT quot_offset_to_pc(F_QUOTATION *quot, F_FIXNUM offset) diff --git a/vm/jit.h b/vm/jit.h index b3a54d604f..26a67490f4 100644 --- a/vm/jit.h +++ b/vm/jit.h @@ -1,3 +1,2 @@ -DLLEXPORT void jit_compile(F_QUOTATION *quot); -jit_compile_all(void); +DLLEXPORT FASTCALL void jit_compile(CELL tagged, F_STACK_FRAME *stack); XT quot_offset_to_pc(F_QUOTATION *quot, F_FIXNUM offset); diff --git a/vm/layouts.h b/vm/layouts.h index e5419d1470..fc59802f36 100644 --- a/vm/layouts.h +++ b/vm/layouts.h @@ -194,6 +194,8 @@ typedef struct { CELL header; /* tagged */ CELL array; + /* tagged */ + CELL compiled; /* untagged */ XT xt; } F_QUOTATION; diff --git a/vm/run.c b/vm/run.c index 2b946b0722..255be845d3 100644 --- a/vm/run.c +++ b/vm/run.c @@ -20,23 +20,21 @@ void uncurry(CELL obj) } } -void update_xt(F_WORD* word) +XT default_word_xt(F_WORD *word) { - word->compiledp = F; - if(word->def == T) - word->xt = dosym; + return dosym; else if(type_of(word->def) == QUOTATION_TYPE) { if(profiling) - word->xt = docol_profiling; + return docol_profiling; else - word->xt = docol; + return docol; } else if(type_of(word->def) == FIXNUM_TYPE) - word->xt = primitives[to_fixnum(word->def)]; + return primitives[to_fixnum(word->def)]; else - word->xt = undefined; + return undefined; } DEFINE_PRIMITIVE(uncurry) diff --git a/vm/run.h b/vm/run.h index 4d031350d3..72ee7eea17 100644 --- a/vm/run.h +++ b/vm/run.h @@ -145,7 +145,7 @@ INLINE CELL type_of(CELL tagged) DEFPUSHPOP(d,ds) DEFPUSHPOP(r,rs) -void update_xt(F_WORD* word); +XT default_word_xt(F_WORD *word); DECLARE_PRIMITIVE(execute); DECLARE_PRIMITIVE(call); diff --git a/vm/types.c b/vm/types.c index a17999a98b..d6cb96508a 100644 --- a/vm/types.c +++ b/vm/types.c @@ -132,6 +132,7 @@ DEFINE_PRIMITIVE(array_to_quotation) F_QUOTATION *quot = allot_object(QUOTATION_TYPE,sizeof(F_QUOTATION)); quot->array = dpeek(); quot->xt = lazy_jit_compile; + quot->compiled = F; drepl(tag_object(quot)); } @@ -477,7 +478,8 @@ F_WORD *allot_word(CELL vocab, CELL name) word->def = F; word->props = F; word->counter = tag_fixnum(0); - update_xt(word); + word->compiledp = F; + word->xt = default_word_xt(word); return word; } @@ -490,7 +492,9 @@ DEFINE_PRIMITIVE(word) DEFINE_PRIMITIVE(update_xt) { - update_xt(untag_word(dpop())); + F_WORD *word = untag_word(dpop()); + word->compiledp = F; + word->xt = default_word_xt(word); } DEFINE_PRIMITIVE(word_xt) From 99a42aa0891e24ca03c68c9329cecb7e243cb44d Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Wed, 26 Sep 2007 00:34:10 -0400 Subject: [PATCH 14/21] Fix crash if GC runs during lazy_jit_compile --- vm/cpu-ppc.S | 2 -- vm/cpu-x86.32.S | 2 +- vm/cpu-x86.64.S | 2 +- vm/jit.c | 7 ++++++- vm/jit.h | 2 +- 5 files changed, 9 insertions(+), 6 deletions(-) diff --git a/vm/cpu-ppc.S b/vm/cpu-ppc.S index ba539c1fdc..295fffa1a5 100644 --- a/vm/cpu-ppc.S +++ b/vm/cpu-ppc.S @@ -173,9 +173,7 @@ DEF(void,throw_impl,(CELL quot, F_STACK_FRAME *rewind_to)): DEF(void,lazy_jit_compile,(CELL quot)): mr r4,r1 /* save stack pointer */ PROLOGUE - SAVE(r3,18) /* save quot */ bl MANGLE(jit_compile) - RESTORE(r3,18) EPILOGUE JUMP_QUOT /* call the quotation */ diff --git a/vm/cpu-x86.32.S b/vm/cpu-x86.32.S index 19a735ec88..d8630ce9b3 100644 --- a/vm/cpu-x86.32.S +++ b/vm/cpu-x86.32.S @@ -20,7 +20,7 @@ and the callstack top is passed in EDX */ pop %ebp ; \ pop %ebx -#define QUOT_XT_OFFSET 5 +#define QUOT_XT_OFFSET 9 #define PROFILING_OFFSET 25 #define WORD_DEF_OFFSET 13 #define WORD_XT_OFFSET 29 diff --git a/vm/cpu-x86.64.S b/vm/cpu-x86.64.S index 1725c0cbd5..6cddb7e53b 100644 --- a/vm/cpu-x86.64.S +++ b/vm/cpu-x86.64.S @@ -20,7 +20,7 @@ pop %rbp ; \ pop %rbx -#define QUOT_XT_OFFSET 13 +#define QUOT_XT_OFFSET 21 #define PROFILING_OFFSET 53 #define WORD_DEF_OFFSET 29 #define WORD_XT_OFFSET 61 diff --git a/vm/jit.c b/vm/jit.c index d10f25c325..6faf0a6a17 100644 --- a/vm/jit.c +++ b/vm/jit.c @@ -34,10 +34,12 @@ bool jit_stack_frame_p(F_ARRAY *array) return false; } -FASTCALL void jit_compile(CELL tagged, F_STACK_FRAME *stack) +FASTCALL CELL jit_compile(CELL tagged, F_STACK_FRAME *stack) { stack_chain->callstack_top = stack; + REGISTER_ROOT(tagged); + F_QUOTATION *quot = untag_quotation(tagged); F_ARRAY *array = untag_object(quot->array); @@ -154,6 +156,9 @@ FASTCALL void jit_compile(CELL tagged, F_STACK_FRAME *stack) UNREGISTER_UNTAGGED(quot); quot->xt = xt; quot->compiled = T; + + UNREGISTER_ROOT(tagged); + return tagged; } XT quot_offset_to_pc(F_QUOTATION *quot, F_FIXNUM offset) diff --git a/vm/jit.h b/vm/jit.h index 26a67490f4..a9f1399472 100644 --- a/vm/jit.h +++ b/vm/jit.h @@ -1,2 +1,2 @@ -DLLEXPORT FASTCALL void jit_compile(CELL tagged, F_STACK_FRAME *stack); +DLLEXPORT FASTCALL CELL jit_compile(CELL tagged, F_STACK_FRAME *stack); XT quot_offset_to_pc(F_QUOTATION *quot, F_FIXNUM offset); From 30fdd20f96cd4f09d368b6d8a360aadbd57f07ec Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Wed, 26 Sep 2007 00:34:37 -0400 Subject: [PATCH 15/21] Update x86 for lazy JIT --- vm/cpu-x86.32.S | 1 + vm/cpu-x86.64.S | 1 + vm/cpu-x86.S | 12 ++++++++++++ 3 files changed, 14 insertions(+) diff --git a/vm/cpu-x86.32.S b/vm/cpu-x86.32.S index d8630ce9b3..6233b4a14f 100644 --- a/vm/cpu-x86.32.S +++ b/vm/cpu-x86.32.S @@ -9,6 +9,7 @@ and the callstack top is passed in EDX */ #define XT_REG %ecx #define STACK_REG %esp #define DS_REG %esi +#define RETURN_REG %eax #define CELL_SIZE 4 diff --git a/vm/cpu-x86.64.S b/vm/cpu-x86.64.S index 6cddb7e53b..4e8faa18de 100644 --- a/vm/cpu-x86.64.S +++ b/vm/cpu-x86.64.S @@ -5,6 +5,7 @@ #define XT_REG %rcx #define STACK_REG %rsp #define DS_REG %r14 +#define RETURN_REG %rax #define CELL_SIZE 8 diff --git a/vm/cpu-x86.S b/vm/cpu-x86.S index 3e2a97dd5c..ec5d09291e 100644 --- a/vm/cpu-x86.S +++ b/vm/cpu-x86.S @@ -51,3 +51,15 @@ DEF(FASTCALL void,primitive_execute,(void)): DEF(FASTCALL void,throw_impl,(CELL quot, F_STACK_FRAME *rewind_to)): mov ARG1,STACK_REG /* rewind_to */ JUMP_QUOT + +DEF(FASTCALL void,lazy_jit_compile,(CELL quot)): + mov STACK_REG,ARG1 /* Save stack pointer */ + push XT_REG /* Alignment */ + push XT_REG + push XT_REG + call MANGLE(jit_compile) + mov RETURN_REG,ARG0 /* No-op on 32-bit */ + pop XT_REG /* OK to clobber XT_REG here */ + pop XT_REG + pop XT_REG + JUMP_QUOT /* Call the quotation */ From b28dd55121c3604a24febba3f6a389a88744d873 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Wed, 26 Sep 2007 00:42:11 -0400 Subject: [PATCH 16/21] x86 compile fix --- vm/cpu-x86.h | 1 + 1 file changed, 1 insertion(+) diff --git a/vm/cpu-x86.h b/vm/cpu-x86.h index a535038eef..63bf2b08e1 100644 --- a/vm/cpu-x86.h +++ b/vm/cpu-x86.h @@ -28,5 +28,6 @@ FASTCALL void undefined(CELL word); FASTCALL void dosym(CELL word); FASTCALL void docol_profiling(CELL word); FASTCALL void docol(CELL word); +FASTCALL void lazy_jit_compile(CELL quot); void set_callstack(F_STACK_FRAME *to, F_STACK_FRAME *from, CELL length, void *memcpy); From abb4b02b04cc0ecb0a6e3a8e32a9ad1cdf95e74b Mon Sep 17 00:00:00 2001 From: Eduardo Cavazos Date: Wed, 26 Sep 2007 15:40:48 -0500 Subject: [PATCH 17/21] boids.ui: factor the drawing code a bit --- extra/boids/ui/ui.factor | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/extra/boids/ui/ui.factor b/extra/boids/ui/ui.factor index 8b8b4665b8..2bd86f49f6 100644 --- a/extra/boids/ui/ui.factor +++ b/extra/boids/ui/ui.factor @@ -18,7 +18,7 @@ USING: kernel namespaces ui.gadgets.packs ui.gadgets.grids ui.gestures - hashtables.lib vars rewrite-closures boids ; + combinators.lib hashtables.lib vars rewrite-closures boids ; IN: boids.ui @@ -26,16 +26,13 @@ IN: boids.ui ! draw-boid ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -: boid-point-a ( boid -- a ) boid-pos ; +: point-a ( boid -- a ) boid-pos ; -: boid-point-b ( boid -- b ) dup boid-pos swap boid-vel normalize* 20 v*n v+ ; +: point-b ( boid -- b ) [ boid-pos ] [ boid-vel normalize* 20 v*n ] bi v+ ; -: boid-points ( boid -- point-a point-b ) dup boid-point-a swap boid-point-b ; +: boid-points ( boid -- point-a point-b ) [ point-a ] [ point-b ] bi ; -: draw-line ( a b -- ) -GL_LINES glBegin first2 glVertex2d first2 glVertex2d glEnd ; - -: draw-boid ( boid -- ) boid-points draw-line ; +: draw-boid ( boid -- ) boid-points gl-line ; : draw-boids ( -- ) boids> [ draw-boid ] each ; From 2ff05e749651c5a0aaa13c937220353470c1ac9f Mon Sep 17 00:00:00 2001 From: Eduardo Cavazos Date: Wed, 26 Sep 2007 16:42:07 -0500 Subject: [PATCH 18/21] minor boids change --- extra/boids/boids.factor | 2 -- 1 file changed, 2 deletions(-) diff --git a/extra/boids/boids.factor b/extra/boids/boids.factor index aa3311ada5..3c29f895d7 100644 --- a/extra/boids/boids.factor +++ b/extra/boids/boids.factor @@ -79,8 +79,6 @@ VAR: separation-radius ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -! : relative-position ( self other -- v ) boid-pos swap boid-pos v- ; - : relative-position ( self other -- v ) swap [ boid-pos ] 2apply v- ; : relative-angle ( self other -- angle ) From 08192267fec5f34a3d898d45f5e0632522f449ce Mon Sep 17 00:00:00 2001 From: Eduardo Cavazos Date: Wed, 26 Sep 2007 16:43:17 -0500 Subject: [PATCH 19/21] ui.gadgets.slate: call doesn't work on 'f'. fix related pit. --- extra/ui/gadgets/slate/slate.factor | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/extra/ui/gadgets/slate/slate.factor b/extra/ui/gadgets/slate/slate.factor index 05e36c48b0..5ea1ec20fa 100644 --- a/extra/ui/gadgets/slate/slate.factor +++ b/extra/ui/gadgets/slate/slate.factor @@ -8,7 +8,9 @@ TUPLE: slate action dim graft ungraft ; : ( action -- slate ) slate construct-gadget tuck set-slate-action - { 100 100 } over set-slate-dim ; + { 100 100 } over set-slate-dim + [ ] over set-slate-graft + [ ] over set-slate-ungraft ; M: slate pref-dim* ( slate -- dim ) slate-dim ; From 4ca59092cabfd5bee6f4d7d99d93ffb9c9d48747 Mon Sep 17 00:00:00 2001 From: Eduardo Cavazos Date: Wed, 26 Sep 2007 16:43:56 -0500 Subject: [PATCH 20/21] Refactor cfdg.hsv using combinators --- extra/cfdg/hsv/hsv.factor | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/extra/cfdg/hsv/hsv.factor b/extra/cfdg/hsv/hsv.factor index bd33eb3529..3714416d2e 100644 --- a/extra/cfdg/hsv/hsv.factor +++ b/extra/cfdg/hsv/hsv.factor @@ -1,5 +1,5 @@ -USING: kernel combinators arrays sequences math ; +USING: kernel combinators arrays sequences math combinators.lib ; IN: cfdg.hsv @@ -15,13 +15,13 @@ IN: cfdg.hsv : Hi ( hsv -- Hi ) H 60 / floor 6 mod ; -: f ( hsv -- f ) dup H 60 / swap Hi - ; +: f ( hsv -- f ) [ H 60 / ] [ Hi ] bi - ; -: p ( hsv -- p ) 1 over S - swap V * ; +: p ( hsv -- p ) [ S 1 swap - ] [ V ] bi * ; -: q ( hsv -- q ) dup f over S * 1 swap - swap V * ; +: q ( hsv -- q ) [ [ f ] [ S ] bi * 1 swap - ] [ V ] bi * ; -: t ( hsv -- t ) 1 over f - over S * 1 swap - swap V * ; +: t ( hsv -- t ) [ [ f 1 swap - ] [ S ] bi * 1 swap - ] [ V ] bi * ; PRIVATE> @@ -31,9 +31,9 @@ PRIVATE> : hsv>rgb ( hsv -- rgb ) dup Hi -{ { 0 [ dup V swap dup t swap p ] } - { 1 [ dup q over V rot p ] } - { 2 [ dup p over V rot t ] } - { 3 [ dup p over q rot V ] } - { 4 [ dup t over p rot V ] } - { 5 [ dup V over p rot q ] } } case 3array ; \ No newline at end of file +{ { 0 [ [ V ] [ t ] [ p ] tri ] } + { 1 [ [ q ] [ V ] [ p ] tri ] } + { 2 [ [ p ] [ V ] [ t ] tri ] } + { 3 [ [ p ] [ q ] [ V ] tri ] } + { 4 [ [ t ] [ p ] [ V ] tri ] } + { 5 [ [ V ] [ p ] [ q ] tri ] } } case 3array ; From 5041d0a46a9199138cd9e4bff9f712e27b08fa67 Mon Sep 17 00:00:00 2001 From: Eduardo Cavazos Date: Wed, 26 Sep 2007 16:44:58 -0500 Subject: [PATCH 21/21] Update cfdg models: call doesn't work on 'f'. fix related pits. --- extra/cfdg/models/flower6/flower6.factor | 1 + extra/cfdg/models/lesson/lesson.factor | 1 + extra/cfdg/models/snowflake/snowflake.factor | 1 + 3 files changed, 3 insertions(+) diff --git a/extra/cfdg/models/flower6/flower6.factor b/extra/cfdg/models/flower6/flower6.factor index cae8024b50..b77968c863 100644 --- a/extra/cfdg/models/flower6/flower6.factor +++ b/extra/cfdg/models/flower6/flower6.factor @@ -19,6 +19,7 @@ iterate? [ ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! : run ( -- ) +[ ] >background { -1 2 -1 2 } viewport set 0.01 threshold set [ flower6 ] start-shape set diff --git a/extra/cfdg/models/lesson/lesson.factor b/extra/cfdg/models/lesson/lesson.factor index bd3f7914d8..26934aa182 100644 --- a/extra/cfdg/models/lesson/lesson.factor +++ b/extra/cfdg/models/lesson/lesson.factor @@ -97,6 +97,7 @@ iterate? [ ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! : run ( -- ) +[ ] >background { -5 25 -15 25 } viewport set 0.03 threshold set [ toc ] start-shape set diff --git a/extra/cfdg/models/snowflake/snowflake.factor b/extra/cfdg/models/snowflake/snowflake.factor index 42e0b3e304..e42c297581 100644 --- a/extra/cfdg/models/snowflake/snowflake.factor +++ b/extra/cfdg/models/snowflake/snowflake.factor @@ -26,6 +26,7 @@ spike ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! : run ( -- ) +[ ] >background { -40 80 -40 80 } viewport set 0.1 threshold set [ snowflake ] start-shape set