Merge branch 'master' into scenes

snap7
jmoenig 2021-06-23 19:10:14 +02:00
commit 4f2aedc93e
7 zmienionych plików z 430 dodań i 14 usunięć

Wyświetl plik

@ -95,11 +95,20 @@
* **New Features:**
* new extension primitives
* **Notable Changes:**
* libraries no longer rely on the JSF primitive, project may need to re-import their libraries to run without having to enable JS exstensions
* libraries no longer rely on the JSF primitive, project may need to re-import their libraries to run without having to enable JS extensions
* retired Leap Motion library, took out Hummingbird library (get the current one from Birdbrain)
* **Notable Fixes:**
* fixed occasional invisible error messages
### 2021-06-19
### 2021-06-23
* updated bignums library
* pushed dev version to 6.10
* took out device libraries (Hummingbird blocks and Leap Motion)
### 2021-06-22
* extensions: added script-loading extension primitive
### 2021-06-20
* updated extensions documentation
### 2021-06-19

Wyświetl plik

@ -28,9 +28,3 @@ stream-tools.xml Streams (lazy lists) A variation on the list data type in which
bar-charts.xml Bar charts Takes a table (typically from a CSV data set) as input and reports a summary of the table grouped by the field in the specified column number. The remaining three inputs are used only if the field values are numbers, in which case they can be grouped into buckets (e.g., decades, centuries, etc.). Those three inputs specify the smallest and largest values of interest and, most importantly, the width of a bucket (10 for decades, 100 for centuries). If the field isn't numeric, leave these three inputs empty or set them to zero. In that case, each string value of the field is its own bucket, and they appear sorted alphabetically. The block reports a new table with three columns. The first column contains the bucket name or smallest number. The second column contains a nonnegative integer that says how many records in the input table fall into this bucket. The third column is a subtable containing the actual records from the original table that fall into the bucket. If your buckets aren't of constant width, or you want to group by some function of more than one field, load the "Frequency Distribution Analysis" library instead.
httpBlocks.xml Web services access (https) An extended version of the URL block that allows POST, PUT, and DELETE as well as GET requests, allows using the secure HTTPS protocol, and gives control over headers, etc. Also parses JSON data.
make-variables.xml Create variables Create and manage global/sprite/script variables in a script
~ ~
~ ~
~ ~
HummingbirdBlocks.xml Hummingbird robotics Control the Hummingbird robotics kit processor
leap-library.xml LEAP Motion controller Report hand positions from LEAP Motion controller (leapmotion.com).

File diff suppressed because one or more lines are too long

Wyświetl plik

@ -0,0 +1,375 @@
makeGlobalObject();
SnapExtensions.primitives.set(
'big_switch(bool)',
loadBlocks
);
SnapExtensions.primitives.set(
'big_scheme(fn, num)',
function (which, num) {
function parseNumber (n) {
var fn = SchemeNumber.fn;
if (!fn['number?'](n)) {
n = '' + n;
try {
return parseENotation(n) || SchemeNumber(n);
} catch (err) {
return NaN;
}
}
return n;
}
function parseENotation (n) {
var fn = SchemeNumber.fn;
var numbers = n.match(/^(-?\d+\.?\d*|-?\.\d+)e(-?\d+)$/i);
if (!numbers) return null;
var coefficient = numbers[1];
var exponent = numbers[2];
return fn['*'](
coefficient,
fn.expt('10', exponent)
);
}
var fn=SchemeNumber.fn,
number=parseNumber(num);
switch (which) {
case 'number?':
case 'complex?':
return (fn['number?'](number));
case 'real?':
return (fn['real?'](number) || fn['real-valued?'](number));
case 'rational?':
return (fn['rational?'](number) || (fn['='](number, fn.rationalize(number, parseNumber('1.0e-5')))));
case 'integer?':
return (fn['integer?'](number) || fn['integer-valued?'](number));
case 'exact?':
case 'inexact?':
case 'finite?':
case 'infinite?':
case 'nan?':
case 'real-part':
case 'imag-part':
return (fn[which](number));
case 'magnitude':
return (fn.magnitude(number));
case 'angle':
return (fn.angle(number));
case 'numerator':
return (fn.numerator(number));
case 'denominator':
return (fn.denominator(number));
case 'exact':
return (fn.exact(number));
case 'inexact':
return (fn.inexact(number));
}
}
);
function makeGlobalObject () {
window.bigNumbers = {
originalEvaluate: InputSlotMorph.prototype.evaluate,
originalChangeVar: VariableFrame.prototype.changeVar,
originalPrims: {
reportBasicSum: Process.prototype.reportBasicSum,
reportBasicDifference: Process.prototype.reportBasicDifference,
reportBasicProduct: Process.prototype.reportBasicProduct,
reportBasicQuotient: Process.prototype.reportBasicQuotient,
reportBasicPower: Process.prototype.reportBasicPower,
reportBasicModulus: Process.prototype.reportBasicModulus,
reportBasicAtan2: Process.prototype.reportBasicAtan2,
reportRound: Process.prototype.reportRound,
reportBasicMin: Process.prototype.reportBasicMin,
reportBasicMax: Process.prototype.reportBasicMax,
reportBasicRandom: Process.prototype.reportBasicRandom,
reportBasicLessThan: Process.prototype.reportBasicLessThan,
reportBasicGreaterThan: Process.prototype.reportBasicGreaterThan,
reportEquals: Process.prototype.reportEquals,
reportIsIdentical: Process.prototype.reportIsIdentical,
reportMonadic: Process.prototype.reportMonadic
}
};
}
function loadBlocks (useBigNums) {
var fn = SchemeNumber.fn;
var originalPrims = window.bigNumbers.originalPrims;
if (useBigNums) {
InputSlotMorph.prototype.evaluate = function () {
var contents = this.contents();
if (this.selectedBlock) {
return this.selectedBlock;
}
if (this.constant) {
return this.constant;
}
if (this.isNumeric) {
return parseNumber(contents.text || '0');
}
return contents.text;
};
VariableFrame.prototype.changeVar = function (name, delta, sender) {
var frame = this.find(name),
value,
newValue;
if (frame) {
value = parseNumber(frame.vars[name].value);
newValue = Number.isNaN(value) ? delta : fn['+'](value, parseNumber(delta));
if (sender instanceof SpriteMorph &&
(frame.owner instanceof SpriteMorph) &&
(sender !== frame.owner)) {
sender.shadowVar(name, newValue);
} else {
frame.vars[name].value = newValue;
}
}
};
Object.assign(Process.prototype, {
reportBasicSum: function (a, b) {
a = parseNumber(a);
b = parseNumber(b);
if (Number.isNaN(a) || Number.isNaN(b)) return NaN;
return fn['+'](a, b);
},
reportBasicDifference: function (a, b) {
a = parseNumber(a);
b = parseNumber(b);
if (Number.isNaN(a) || Number.isNaN(b)) return NaN;
return fn['-'](a, b);
},
reportBasicProduct: function (a, b) {
a = parseNumber(a);
b = parseNumber(b);
if (Number.isNaN(a) || Number.isNaN(b)) return NaN;
return fn['*'](a, b);
},
reportBasicQuotient: function (a, b) {
a = parseNumber(a);
b = parseNumber(b);
if (fn['='](b, '0') && !fn['='](a, '0')) {
return (fn['<'](a, '0') ? SchemeNumber('-inf.0') : SchemeNumber('+inf.0'))
};
if (Number.isNaN(a) || Number.isNaN(b) || fn['='](b, '0')) return NaN;
return fn['/'](a, b);
},
reportBasicPower: function (a, b) {
a = parseNumber(a);
b = parseNumber(b);
if (Number.isNaN(a) || Number.isNaN(b)) return NaN;
return fn['expt'](a, b);
},
reportBasicModulus: function (a, b) {
a = parseNumber(a);
b = parseNumber(b);
if (Number.isNaN(a) || Number.isNaN(b)) return NaN;
var result = fn.mod(a, b);
if (fn['<'](b, '0') && fn['>'](result, '0')) {
result = fn['+'](result, b);
}
return result;
},
reportBasicAtan2: function (a, b) {
a = parseNumber(a);
b = parseNumber(b);
if (Number.isNaN(a) || Number.isNaN(b)) return NaN;
return degrees(fn.atan2(a, b));
},
reportRound: function (n) {
if (this.enableHyperOps) {
if (n instanceof List) {
return n.map(each => this.reportRound(each));
}
}
n = parseNumber(n);
if (Number.isNaN(n)) return NaN;
x = fn.round(n);
if (fn["integer?"](x)) return fn["exact"](x);
return x;
},
reportBasicMin: function (a, b) {
x = parseNumber(a);
y = parseNumber(b);
if (Number.isNaN(x) || Number.isNaN(y)) {
return a<b ? a : b;
}
return fn['<'](x, y) ? x : y;
},
reportBasicMax: function (a, b) {
x = parseNumber(a);
y = parseNumber(b);
if (Number.isNaN(x) || Number.isNaN(y)) {
return a>b ? a : b;
}
return fn['>'](x, y) ? x : y;
},
reportBasicRandom: function (min, max) {
var floor = parseNumber(min),
ceil = parseNumber(max);
if (Number.isNaN(floor) || Number.isNaN(ceil)) return NaN;
if (!fn['='](fn.mod(floor, '1'), '0') || !fn['='](fn.mod(ceil, '1'), '0')) {
// One of the numbers isn't whole. Include the decimal.
return fn['+'](
fn['*'](
Math.random(),
fn['-'](ceil, floor)
),
floor
);
}
var size = Math.ceil(max.toString(10).length/14);
const array = new Uint32Array(size);
window.crypto.getRandomValues(array);
var digits="";
for (i=0;i<size;i++) {
digits = digits + array[i].toString();
}
return fn.floor(
fn['+'](
// fn['*'](
// Math.random(),
fn.mod(parseNumber(digits),
fn['+'](
fn['-'](ceil, floor),
'1'
)
),
floor
)
);
},
reportBasicLessThan: function (a, b) {
x = parseNumber(a);
y = parseNumber(b);
if (Number.isNaN(x) || Number.isNaN(y)) return a<b;
return fn['<'](x, y);
},
reportBasicGreaterThan: function (a, b) {
x = parseNumber(a);
y = parseNumber(b);
if (Number.isNaN(x) || Number.isNaN(y)) return a>b;
return fn['>'](x, y);
},
reportEquals: function (a, b) {
x = parseNumber(a);
y = parseNumber(b);
if (Number.isNaN(x) || Number.isNaN(y)) return snapEquals(a, b);
return fn['='](x, y);
},
reportIsIdentical: function (a, b) {
x = parseNumber(a);
y = parseNumber(b);
if (Number.isNaN(x) || Number.isNaN(y)) return originalPrims.reportIsIdentical(a, b);
return fn['='](x, y);
},
reportMonadic: function (fname, n) {
if (this.enableHyperOps) {
if (n instanceof List) {
return n.map(each => this.reportMonadic(fname, each));
}
}
n = parseNumber(n);
if (Number.isNaN(n)) return NaN;
switch (Process.prototype.inputOption(fname)) {
case 'abs':
return fn.abs(n);
case 'neg':
return fn['-'](n);
case 'sign':
if (fn['='](n,SchemeNumber('0'))) return SchemeNumber('0');
return fn['/'](n, fn.abs(n));
case 'ceiling':
return fn.ceiling(n);
case 'floor':
return fn.floor(n);
case 'sqrt':
return sqrt(n);
case 'sin':
return fn.sin(radians(n));
case 'cos':
return fn.cos(radians(n));
case 'tan':
return fn.tan(radians(n));
case 'asin':
return degrees(fn.asin(n));
case 'acos':
return degrees(fn.acos(n));
case 'atan':
return degrees(fn.atan(n));
case 'ln':
return fn.log(n);
case 'log':
return fn.log(n, '10');
case 'lg':
return fn.log(n, '2');
case 'e^':
return fn.exp(n);
case '10^':
return fn.expt('10', n);
case '2^':
return fn.expt('2', n);
case 'id':
return n;
default:
return SchemeNumber('0');
}
}
});
} else {
InputSlotMorph.prototype.evaluate = window.bigNumbers.originalEvaluate;
VariableFrame.prototype.changeVar = window.bigNumbers.originalChangeVar;
Object.assign(Process.prototype, originalPrims);
}
// +++ done = true;
}
function parseNumber (n) {
var fn = SchemeNumber.fn;
if (!fn['number?'](n)) {
n = '' + n;
try {
return parseENotation(n) || SchemeNumber(n);
} catch (err) {
return NaN;
}
}
return n;
}
function parseENotation (n) {
var fn = SchemeNumber.fn;
var numbers = n.match(/^(-?\d+\.?\d*|-?\.\d+)e(-?\d+)$/i);
if (!numbers) return null;
var coefficient = numbers[1];
var exponent = numbers[2];
return fn['*'](
coefficient,
fn.expt('10', exponent)
);
}
function sqrt (n) {
var fn = SchemeNumber.fn;
if (!fn['exact?'](n) || !fn['rational?'](n) || fn['<'](n,'0')) return fn.sqrt(n);
var rootNumerator = fn['exact-integer-sqrt'](fn.numerator(n));
if (!fn['='](rootNumerator[1], '0')) return fn.sqrt(n);
var rootDenominator = fn['exact-integer-sqrt'](fn.denominator(n));
if (!fn['='](rootDenominator[1], '0')) return fn.sqrt(n);
return fn['/'](rootNumerator[0], rootDenominator[0]);
}

Wyświetl plik

@ -12,7 +12,7 @@
<script src="src/threads.js?version=2021-06-18"></script>
<script src="src/objects.js?version=2021-06-14"></script>
<script src="src/scenes.js?version=2021-05-21"></script>
<script src="src/gui.js?version=2021-06-14"></script>
<script src="src/gui.js?version=2021-06-23"></script>
<script src="src/paint.js?version=2020-05-17"></script>
<script src="src/lists.js?version=2021-03-15"></script>
<script src="src/byob.js?version=2021-06-19"></script>
@ -20,7 +20,7 @@
<script src="src/sketch.js?version=2021-03-17"></script>
<script src="src/video.js?version=2019-06-27"></script>
<script src="src/maps.js?version=2021-06-15"></script>
<script src="src/extensions.js?version=2021-06-20"></script>
<script src="src/extensions.js?version=2021-06-23"></script>
<script src="src/xml.js?version=2020-04-27"></script>
<script src="src/store.js?version=2021-06-10"></script>
<script src="src/locale.js?version=2021-06-11"></script>

Wyświetl plik

@ -31,13 +31,17 @@
IDE_Morph, CamSnapshotDialogMorph, SoundRecorderDialogMorph, isSnapObject, nop,
Color, contains*/
modules.extensions = '2021-June-20';
modules.extensions = '2021-June-23';
// Global stuff
var SnapExtensions = {
primitives: new Map(),
menus: new Map()
menus: new Map(),
scripts: [],
urls: [
'libraries/'
]
};
/*
@ -108,6 +112,8 @@ var SnapExtensions = {
Whatever you do, please use these extension capabilities sensibly.
*/
// Primitives
// errors & exceptions (err_):
SnapExtensions.primitives.set(
@ -674,6 +680,38 @@ SnapExtensions.primitives.set(
}
);
// loading external scripts (scr_)
SnapExtensions.primitives.set(
'scr_load(url)',
function (url, proc) {
var scriptElement;
if (!proc.context.accumulator) {
proc.context.accumulator = {done: false};
if (contains(SnapExtensions.scripts, url)) {
return;
}
if (!(SnapExtensions.urls.some(any => url.indexOf(any) === 0))) {
throw new Error('unlisted extension url:\n"' + url + '"');
}
scriptElement = document.createElement('script');
scriptElement.onload = () => {
SnapExtensions.scripts.push(url);
proc.context.accumulator.done = true;
};
document.head.appendChild(scriptElement);
scriptElement.src = url;
} else if (proc.context.accumulator.done) {
return;
}
proc.pushContext('doYield');
proc.pushContext();
}
);
// Menus
SnapExtensions.menus.set(
'clr_numbers', // Brian's browns and oranges, sigh...
function () {

Wyświetl plik

@ -83,7 +83,7 @@ Animation, BoxMorph, BlockDialogMorph, Project, ZERO, BLACK*/
// Global stuff ////////////////////////////////////////////////////////
modules.gui = '2021-June-14';
modules.gui = '2021-June-23';
// Declarations