diff options
author | David Barksdale <amatus@amatus.name> | 2016-09-10 17:58:46 -0500 |
---|---|---|
committer | David Barksdale <amatus@amatus.name> | 2016-09-10 18:32:35 -0500 |
commit | 475f9f3ac7688e58505690d420cafe6ae8bb8b5f (patch) | |
tree | b1bf14b10751fe4e9e146ad7244ec86bb123893d /blockly/generators/php/math.js | |
parent | 923561056ddb63ce82fd1ec2a5e249bbdae267bf (diff) |
Merge blockly sub-tree
Diffstat (limited to 'blockly/generators/php/math.js')
-rw-r--r-- | blockly/generators/php/math.js | 372 |
1 files changed, 372 insertions, 0 deletions
diff --git a/blockly/generators/php/math.js b/blockly/generators/php/math.js new file mode 100644 index 0000000..7789ba8 --- /dev/null +++ b/blockly/generators/php/math.js @@ -0,0 +1,372 @@ +/** + * @license + * Visual Blocks Language + * + * Copyright 2015 Google Inc. + * https://developers.google.com/blockly/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @fileoverview Generating PHP for math blocks. + * @author daarond@gmail.com (Daaron Dwyer) + */ +'use strict'; + +goog.provide('Blockly.PHP.math'); + +goog.require('Blockly.PHP'); + + +Blockly.PHP['math_number'] = function(block) { + // Numeric value. + var code = parseFloat(block.getFieldValue('NUM')); + if (code == Infinity) { + code = 'INF'; + } else if (code == -Infinity) { + code = '-INF'; + } + return [code, Blockly.PHP.ORDER_ATOMIC]; +}; + +Blockly.PHP['math_arithmetic'] = function(block) { + // Basic arithmetic operators, and power. + var OPERATORS = { + 'ADD': [' + ', Blockly.PHP.ORDER_ADDITION], + 'MINUS': [' - ', Blockly.PHP.ORDER_SUBTRACTION], + 'MULTIPLY': [' * ', Blockly.PHP.ORDER_MULTIPLICATION], + 'DIVIDE': [' / ', Blockly.PHP.ORDER_DIVISION], + 'POWER': [' ** ', Blockly.PHP.ORDER_POWER] + }; + var tuple = OPERATORS[block.getFieldValue('OP')]; + var operator = tuple[0]; + var order = tuple[1]; + var argument0 = Blockly.PHP.valueToCode(block, 'A', order) || '0'; + var argument1 = Blockly.PHP.valueToCode(block, 'B', order) || '0'; + var code = argument0 + operator + argument1; + return [code, order]; +}; + +Blockly.PHP['math_single'] = function(block) { + // Math operators with single operand. + var operator = block.getFieldValue('OP'); + var code; + var arg; + if (operator == 'NEG') { + // Negation is a special case given its different operator precedence. + arg = Blockly.PHP.valueToCode(block, 'NUM', + Blockly.PHP.ORDER_UNARY_NEGATION) || '0'; + if (arg[0] == '-') { + // --3 is not legal in JS. + arg = ' ' + arg; + } + code = '-' + arg; + return [code, Blockly.PHP.ORDER_UNARY_NEGATION]; + } + if (operator == 'SIN' || operator == 'COS' || operator == 'TAN') { + arg = Blockly.PHP.valueToCode(block, 'NUM', + Blockly.PHP.ORDER_DIVISION) || '0'; + } else { + arg = Blockly.PHP.valueToCode(block, 'NUM', + Blockly.PHP.ORDER_NONE) || '0'; + } + // First, handle cases which generate values that don't need parentheses + // wrapping the code. + switch (operator) { + case 'ABS': + code = 'abs(' + arg + ')'; + break; + case 'ROOT': + code = 'sqrt(' + arg + ')'; + break; + case 'LN': + code = 'log(' + arg + ')'; + break; + case 'EXP': + code = 'exp(' + arg + ')'; + break; + case 'POW10': + code = 'pow(10,' + arg + ')'; + break; + case 'ROUND': + code = 'round(' + arg + ')'; + break; + case 'ROUNDUP': + code = 'ceil(' + arg + ')'; + break; + case 'ROUNDDOWN': + code = 'floor(' + arg + ')'; + break; + case 'SIN': + code = 'sin(' + arg + ' / 180 * pi())'; + break; + case 'COS': + code = 'cos(' + arg + ' / 180 * pi())'; + break; + case 'TAN': + code = 'tan(' + arg + ' / 180 * pi())'; + break; + } + if (code) { + return [code, Blockly.PHP.ORDER_FUNCTION_CALL]; + } + // Second, handle cases which generate values that may need parentheses + // wrapping the code. + switch (operator) { + case 'LOG10': + code = 'log(' + arg + ') / log(10)'; + break; + case 'ASIN': + code = 'asin(' + arg + ') / pi() * 180'; + break; + case 'ACOS': + code = 'acos(' + arg + ') / pi() * 180'; + break; + case 'ATAN': + code = 'atan(' + arg + ') / pi() * 180'; + break; + default: + throw 'Unknown math operator: ' + operator; + } + return [code, Blockly.PHP.ORDER_DIVISION]; +}; + +Blockly.PHP['math_constant'] = function(block) { + // Constants: PI, E, the Golden Ratio, sqrt(2), 1/sqrt(2), INFINITY. + var CONSTANTS = { + 'PI': ['M_PI', Blockly.PHP.ORDER_ATOMIC], + 'E': ['M_E', Blockly.PHP.ORDER_ATOMIC], + 'GOLDEN_RATIO': ['(1 + sqrt(5)) / 2', Blockly.PHP.ORDER_DIVISION], + 'SQRT2': ['M_SQRT2', Blockly.PHP.ORDER_ATOMIC], + 'SQRT1_2': ['M_SQRT1_2', Blockly.PHP.ORDER_ATOMIC], + 'INFINITY': ['INF', Blockly.PHP.ORDER_ATOMIC] + }; + return CONSTANTS[block.getFieldValue('CONSTANT')]; +}; + +Blockly.PHP['math_number_property'] = function(block) { + // Check if a number is even, odd, prime, whole, positive, or negative + // or if it is divisible by certain number. Returns true or false. + var number_to_check = Blockly.PHP.valueToCode(block, 'NUMBER_TO_CHECK', + Blockly.PHP.ORDER_MODULUS) || '0'; + var dropdown_property = block.getFieldValue('PROPERTY'); + var code; + if (dropdown_property == 'PRIME') { + // Prime is a special case as it is not a one-liner test. + var functionName = Blockly.PHP.provideFunction_( + 'math_isPrime', + ['function ' + Blockly.PHP.FUNCTION_NAME_PLACEHOLDER_ + '($n) {', + ' // https://en.wikipedia.org/wiki/Primality_test#Naive_methods', + ' if ($n == 2 || $n == 3) {', + ' return true;', + ' }', + ' // False if n is NaN, negative, is 1, or not whole.', + ' // And false if n is divisible by 2 or 3.', + ' if (!is_numeric($n) || $n <= 1 || $n % 1 != 0 || $n % 2 == 0 ||' + + ' $n % 3 == 0) {', + ' return false;', + ' }', + ' // Check all the numbers of form 6k +/- 1, up to sqrt(n).', + ' for ($x = 6; $x <= sqrt($n) + 1; $x += 6) {', + ' if ($n % ($x - 1) == 0 || $n % ($x + 1) == 0) {', + ' return false;', + ' }', + ' }', + ' return true;', + '}']); + code = functionName + '(' + number_to_check + ')'; + return [code, Blockly.JavaScript.ORDER_FUNCTION_CALL]; + } + switch (dropdown_property) { + case 'EVEN': + code = number_to_check + ' % 2 == 0'; + break; + case 'ODD': + code = number_to_check + ' % 2 == 1'; + break; + case 'WHOLE': + code = 'is_int(' + number_to_check + ')'; + break; + case 'POSITIVE': + code = number_to_check + ' > 0'; + break; + case 'NEGATIVE': + code = number_to_check + ' < 0'; + break; + case 'DIVISIBLE_BY': + var divisor = Blockly.PHP.valueToCode(block, 'DIVISOR', + Blockly.PHP.ORDER_MODULUS) || '0'; + code = number_to_check + ' % ' + divisor + ' == 0'; + break; + } + return [code, Blockly.PHP.ORDER_EQUALITY]; +}; + +Blockly.PHP['math_change'] = function(block) { + // Add to a variable in place. + var argument0 = Blockly.PHP.valueToCode(block, 'DELTA', + Blockly.PHP.ORDER_ADDITION) || '0'; + var varName = Blockly.PHP.variableDB_.getName( + block.getFieldValue('VAR'), Blockly.Variables.NAME_TYPE); + return varName + ' += ' + argument0 + ';\n'; +}; + +// Rounding functions have a single operand. +Blockly.PHP['math_round'] = Blockly.PHP['math_single']; +// Trigonometry functions have a single operand. +Blockly.PHP['math_trig'] = Blockly.PHP['math_single']; + +Blockly.PHP['math_on_list'] = function(block) { + // Math functions for lists. + var func = block.getFieldValue('OP'); + var list, code; + switch (func) { + case 'SUM': + list = Blockly.PHP.valueToCode(block, 'LIST', + Blockly.PHP.ORDER_FUNCTION_CALL) || 'array()'; + code = 'array_sum(' + list + ')'; + break; + case 'MIN': + list = Blockly.PHP.valueToCode(block, 'LIST', + Blockly.PHP.ORDER_FUNCTION_CALL) || 'array()'; + code = 'min(' + list + ')'; + break; + case 'MAX': + list = Blockly.PHP.valueToCode(block, 'LIST', + Blockly.PHP.ORDER_FUNCTION_CALL) || 'array()'; + code = 'max(' + list + ')'; + break; + case 'AVERAGE': + var functionName = Blockly.PHP.provideFunction_( + 'math_mean', + ['function ' + Blockly.PHP.FUNCTION_NAME_PLACEHOLDER_ + + '($myList) {', + ' return array_sum($myList) / count($myList);', + '}']); + list = Blockly.PHP.valueToCode(block, 'LIST', + Blockly.PHP.ORDER_NONE) || 'array()'; + code = functionName + '(' + list + ')'; + break; + case 'MEDIAN': + var functionName = Blockly.PHP.provideFunction_( + 'math_median', + ['function ' + Blockly.PHP.FUNCTION_NAME_PLACEHOLDER_ + + '($arr) {', + ' sort($arr,SORT_NUMERIC);', + ' return (count($arr) % 2) ? $arr[floor(count($arr)/2)] : ', + ' ($arr[floor(count($arr)/2)] + $arr[floor(count($arr)/2)' + + ' - 1]) / 2;', + '}']); + list = Blockly.PHP.valueToCode(block, 'LIST', + Blockly.PHP.ORDER_NONE) || '[]'; + code = functionName + '(' + list + ')'; + break; + case 'MODE': + // As a list of numbers can contain more than one mode, + // the returned result is provided as an array. + // Mode of [3, 'x', 'x', 1, 1, 2, '3'] -> ['x', 1]. + var functionName = Blockly.PHP.provideFunction_( + 'math_modes', + ['function ' + Blockly.PHP.FUNCTION_NAME_PLACEHOLDER_ + + '($values) {', + ' if (empty($values)) return array();', + ' $counts = array_count_values($values);', + ' arsort($counts); // Sort counts in descending order', + ' $modes = array_keys($counts, current($counts), true);', + ' return $modes;', + '}']); + list = Blockly.PHP.valueToCode(block, 'LIST', + Blockly.PHP.ORDER_NONE) || '[]'; + code = functionName + '(' + list + ')'; + break; + case 'STD_DEV': + var functionName = Blockly.PHP.provideFunction_( + 'math_standard_deviation', + ['function ' + Blockly.PHP.FUNCTION_NAME_PLACEHOLDER_ + + '($numbers) {', + ' $n = count($numbers);', + ' if (!$n) return null;', + ' $mean = array_sum($numbers) / count($numbers);', + ' foreach($numbers as $key => $num) $devs[$key] = ' + + 'pow($num - $mean, 2);', + ' return sqrt(array_sum($devs) / (count($devs) - 1));', + '}']); + list = Blockly.PHP.valueToCode(block, 'LIST', + Blockly.PHP.ORDER_NONE) || '[]'; + code = functionName + '(' + list + ')'; + break; + case 'RANDOM': + var functionName = Blockly.PHP.provideFunction_( + 'math_random_list', + ['function ' + Blockly.PHP.FUNCTION_NAME_PLACEHOLDER_ + + '($list) {', + ' $x = rand(0, count($list)-1);', + ' return $list[$x];', + '}']); + list = Blockly.PHP.valueToCode(block, 'LIST', + Blockly.PHP.ORDER_NONE) || '[]'; + code = functionName + '(' + list + ')'; + break; + default: + throw 'Unknown operator: ' + func; + } + return [code, Blockly.PHP.ORDER_FUNCTION_CALL]; +}; + +Blockly.PHP['math_modulo'] = function(block) { + // Remainder computation. + var argument0 = Blockly.PHP.valueToCode(block, 'DIVIDEND', + Blockly.PHP.ORDER_MODULUS) || '0'; + var argument1 = Blockly.PHP.valueToCode(block, 'DIVISOR', + Blockly.PHP.ORDER_MODULUS) || '0'; + var code = argument0 + ' % ' + argument1; + return [code, Blockly.PHP.ORDER_MODULUS]; +}; + +Blockly.PHP['math_constrain'] = function(block) { + // Constrain a number between two limits. + var argument0 = Blockly.PHP.valueToCode(block, 'VALUE', + Blockly.PHP.ORDER_COMMA) || '0'; + var argument1 = Blockly.PHP.valueToCode(block, 'LOW', + Blockly.PHP.ORDER_COMMA) || '0'; + var argument2 = Blockly.PHP.valueToCode(block, 'HIGH', + Blockly.PHP.ORDER_COMMA) || 'Infinity'; + var code = 'min(max(' + argument0 + ', ' + argument1 + '), ' + + argument2 + ')'; + return [code, Blockly.PHP.ORDER_FUNCTION_CALL]; +}; + +Blockly.PHP['math_random_int'] = function(block) { + // Random integer between [X] and [Y]. + var argument0 = Blockly.PHP.valueToCode(block, 'FROM', + Blockly.PHP.ORDER_COMMA) || '0'; + var argument1 = Blockly.PHP.valueToCode(block, 'TO', + Blockly.PHP.ORDER_COMMA) || '0'; + var functionName = Blockly.PHP.provideFunction_( + 'math_random_int', + ['function ' + Blockly.PHP.FUNCTION_NAME_PLACEHOLDER_ + + '($a, $b) {', + ' if ($a > $b) {', + ' return rand($b, $a);', + ' }', + ' return rand($a, $b);', + '}']); + var code = functionName + '(' + argument0 + ', ' + argument1 + ')'; + return [code, Blockly.PHP.ORDER_FUNCTION_CALL]; +}; + +Blockly.PHP['math_random_float'] = function(block) { + // Random fraction between 0 and 1. + return ['(float)rand()/(float)getrandmax()', Blockly.PHP.ORDER_FUNCTION_CALL]; +}; |