├── demo ├── node_test.js ├── sandbox │ └── shaders.html ├── js │ └── ParametricGeometries.js.download └── demo.html ├── .gitignore ├── img └── heron-source-torus.png ├── src ├── utils.ts ├── heron-normal-form.ts ├── code-builder.ts ├── type-parser.ts ├── heron-compiler.ts ├── heron-refs.ts ├── js-intrinsics.js ├── heron-name-analysis.ts ├── heron-defs.ts ├── heron-statement.ts ├── heron-to-html.ts ├── tests.ts ├── heron-to-js.ts ├── heron-to-glsl.ts ├── heron-package.ts └── heron-to-text.ts ├── tsconfig.json ├── input ├── sandbox │ ├── color.heron │ ├── square-cubes.heron │ ├── geometry-transform.heron │ ├── simple_optimizer.py │ ├── geometry-quaternion.heron │ ├── voronoi-distances.heron │ ├── experiment-with-interfaces.txt │ ├── seascape.heron │ ├── noise.heron │ └── geometry-matrix4x4.heron ├── geometry-vector3.heron ├── test.heron ├── array.heron ├── intrinsics.heron └── geometry-mesh.heron ├── .vscode ├── tasks.json └── launch.json ├── package.json ├── LICENSE ├── tools ├── gen-spec.js └── gen-visitor.js ├── source-browser └── styles.css ├── comparison.md ├── index.html ├── history.md └── assets └── expected-types.txt /demo/node_test.js: -------------------------------------------------------------------------------- 1 | require('./output.js'); 2 | process.exit(); -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/type-inference/.vscode/tasks.json 2 | node_modules/ 3 | -------------------------------------------------------------------------------- /img/heron-source-torus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cdiggins/heron-language/HEAD/img/heron-source-torus.png -------------------------------------------------------------------------------- /src/utils.ts: -------------------------------------------------------------------------------- 1 | export type LabelTypes = 'chooseFunc'|'funcType'; 2 | 3 | export function trace(label: LabelTypes, message: string) { 4 | //console.log(message); 5 | } -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": true, 3 | "compilerOptions": { 4 | "target": "ES5", 5 | "module": "commonjs", 6 | "sourceMap": true, 7 | "outDir": "build", 8 | "noUnusedLocals": true, 9 | "strict": false, 10 | //"noUnusedParameters": true, 11 | }, 12 | "include": [ 13 | "src/*.ts" 14 | ], 15 | "exclude": [ 16 | "node_modules" 17 | ] 18 | } -------------------------------------------------------------------------------- /input/sandbox/color.heron: -------------------------------------------------------------------------------- 1 | module color 2 | { 3 | function HUEtoRGB(hue) { 4 | var H = mod(hue,1.0); 5 | var R = abs(H * 6.0 - 3.0) - 1.0; 6 | var G = 2.0 - abs(H * 6.0 - 2.0); 7 | var B = 2.0 - abs(H * 6.0 - 4.0); 8 | return clamp(vec(R,G,B),0.0,1.0); 9 | } 10 | 11 | function HSLtoRGB(HSL) { 12 | var RGB = HUEtoRGB(HSL.x); 13 | var C = (1.0 - abs(2.0 * HSL.z - 1.0)) * HSL.y; 14 | return (RGB - 0.5) * C.vector + HSL.z.vector; 15 | } 16 | } -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.1.0", 3 | 4 | // The command is tsc. 5 | "command": "tsc", 6 | 7 | // Show the output window only if unrecognized errors occur. 8 | "showOutput": "always", 9 | 10 | // Under windows use tsc.exe. This ensures we don't need a shell. 11 | "windows": { 12 | "command": "tsc" 13 | }, 14 | 15 | // args is the program to compile. 16 | "args": ["--watch"], 17 | 18 | "isShellCommand": true, 19 | 20 | // use the standard tsc problem matcher to find compile problems 21 | // in the output. 22 | "problemMatcher": "$tsc" 23 | } -------------------------------------------------------------------------------- /input/sandbox/square-cubes.heron: -------------------------------------------------------------------------------- 1 | // My implementation of some F# code found at: 2 | // https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/active-patterns 3 | 4 | module squarecubes:1.0 5 | { 6 | var err = 1.e-10 7 | 8 | function isInteger(x) 9 | = abs(x - x.round) < err; 10 | 11 | function isSquare(x) 12 | = x.float.sqrt.isInteger; 13 | 14 | function isCube(x) 15 | = x.float.pow(1/3).isInteger; 16 | 17 | function isSquareCube(x) 18 | = x.isSquare || x.isCube; 19 | 20 | var test 21 | = (1 .. 1000000).filter(isSquareCube); 22 | } -------------------------------------------------------------------------------- /input/sandbox/geometry-transform.heron: -------------------------------------------------------------------------------- 1 | language heron:std:0.1; 2 | 3 | module heron:geometry.transform:0.1 4 | { 5 | function transform(pos, rot, scl) 6 | = { position=pos; rotation=rot; scale=scl; }; 7 | 8 | function translation(pos) 9 | = transform(pos, quaternion_zero, ones); 10 | 11 | function rotation(rot) 12 | = transform(origin, rot, ones); 13 | 14 | function scaling(scl) 15 | = transform(origin, quaternion_zero, scl); 16 | 17 | function matrix(t) 18 | = translation_rotation_scaling_matrix(t.position, t.rotation, t.scale); 19 | } 20 | -------------------------------------------------------------------------------- /input/sandbox/simple_optimizer.py: -------------------------------------------------------------------------------- 1 | // https://www.codementor.io/zhuojiadai/julia-vs-r-vs-python-simple-optimization-gnqi4njro 2 | 3 | import numpy as np 4 | from scipy.optimize import minimize 5 | from scipy.stats import norm 6 | 7 | # generate the data 8 | odr=[0.10,0.20,0.15,0.22,0.15,0.10,0.08,0.09,0.12] 9 | Q_t = norm.ppf(odr) 10 | maxQ_t = max(Q_t) 11 | 12 | # define a function that will return a return to optimize based on the input data 13 | def neglik_trunc_tn(Q_t): 14 | maxQ_t = max(Q_t) 15 | def neglik_trunc_fn(musigma): 16 | return -sum(norm.logpdf(Q_t, musigma[0], musigma[1])) + len(Q_t)*norm.logcdf(maxQ_t, musigma[0], musigma[1]) 17 | return neglik_trunc_fn 18 | 19 | # the likelihood function to optimize 20 | neglik = neglik_trunc_tn(Q_t) 21 | 22 | # optimize! 23 | res = minimize(neglik, [np.mean(Q_t), np.std(Q_t)]) 24 | res -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "heron-lang", 3 | "version": "0.3.0", 4 | "description": "A cross-platform programming language inspired by JavaScript that emphasizes simplicity, safety, and code reuse.", 5 | "main": "src/heron.js", 6 | "homepage": "https://github.com/cdiggins/heron-language", 7 | "bugs": "https://github.com/cdiggins/heron-language/issues", 8 | "license": "MIT", 9 | "author": { 10 | "name": "Christopher Diggins", 11 | "email": "cdiggins@gmail.com" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "https://github.com/cdiggins/heron-language.git" 16 | }, 17 | "scripts": { 18 | "build": "tsc", 19 | "watch": "tsc --watch", 20 | "lint": "tslint --project ." 21 | }, 22 | "dependencies": { 23 | "myna-parser": "^2.5.1" 24 | }, 25 | "devDependencies": { 26 | "tslint": "^5.9.1" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/heron-normal-form.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Heron Normal Form (HNF) 3 | * 4 | * An intermediate compiler representation for optimization, transformation, code-generation, 5 | * analysis, and evaluation. 6 | * 7 | * Expression ::= 8 | * | Non-function (Bool, Int, Float, String, etc.) 9 | * | Function 10 | * | Function Set (Array of possible functions) 11 | * | Closure (Function + Closure record) 12 | * | Free variable (reference to entry in closure record) 13 | * | Parameter (bound variable) 14 | * | Function call (Function + Array of Expressions) 15 | * | Condition ( Expression ? Expression : Expression ) 16 | * 17 | * Other intermediate forms to look at: 18 | * * https://en.wikipedia.org/wiki/A-normal_form. 19 | * * https://en.wikipedia.org/wiki/Static_single_assignment_form 20 | * * https://en.wikipedia.org/wiki/Continuation-passing_style 21 | */ 22 | 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Christopher Diggins 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /tools/gen-spec.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const Myna = require("myna-parser"); 4 | const g = require('../build/heron-parser').heronGrammar; 5 | const fs = require('fs'); 6 | 7 | const m = Myna.Myna; 8 | const pkg = JSON.parse(fs.readFileSync('./package.json', "utf8")); 9 | const version = pkg.version; 10 | const schema = m.astSchemaToString('heron'); 11 | const grammar = m.grammarToString('heron'); 12 | 13 | const contents = 14 | [ 15 | '# Heron Specification ' + version, 16 | '', 17 | '## AST Schema', 18 | '', 19 | 'This is the schema of the abstract syntax tree (AST) created when', 20 | 'when parsing Heron with the [Myna parser](https://github.com/cdiggins/myna-parser)', 21 | 'prior to any transformations', 22 | '', 23 | '```', 24 | schema, 25 | '```', 26 | '', 27 | '## PEG Grammar', 28 | '', 29 | 'This is the full grammar for Heron in PEG form. ', 30 | 'Alternatively you can view the [source code for the parser](https://github.com/cdiggins/heron-language/blob/master/src/heron-parser.ts)', 31 | '', 32 | '```', 33 | grammar, 34 | '```' 35 | ].join('\n'); 36 | 37 | fs.writeFileSync('./spec.md', contents); 38 | 39 | process.exit(); 40 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible Node.js debug attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | 8 | { 9 | "type": "node", 10 | "request": "launch", 11 | "name": "Heron Test Output", 12 | "program": "${workspaceRoot}/demo/node_test.js", 13 | "cwd": "${workspaceRoot}", 14 | "outFiles": ["${workspaceRoot}/build/**/*.js"], 15 | "sourceMaps": true 16 | }, 17 | { 18 | "type": "node", 19 | "request": "launch", 20 | "name": "Launch Program", 21 | "program": "${workspaceRoot}/build/tests.js", 22 | "cwd": "${workspaceRoot}", 23 | "outFiles": ["${workspaceRoot}/build/**/*.js"], 24 | "sourceMaps": true 25 | }, 26 | { 27 | "type": "node", 28 | "request": "attach", 29 | "name": "Attach to Process", 30 | "port": 5858, 31 | "outFiles": [], 32 | "timeout": 30000, 33 | "sourceMaps": true 34 | } 35 | ] 36 | } -------------------------------------------------------------------------------- /src/code-builder.ts: -------------------------------------------------------------------------------- 1 | //===================================== 2 | // Helper class for constructing pretty printerd code 3 | // this is passed as a "state" object to visitors 4 | 5 | function count(s: string, sub: string) { 6 | return s.split(sub).length - 1; 7 | } 8 | 9 | export class CodeBuilder 10 | { 11 | lines: string[] = []; 12 | indent: number = 0; 13 | get indentString() { 14 | let r = ''; 15 | for (let i=0; i < this.indent; ++i) 16 | r += ' '; 17 | return r; 18 | } 19 | pushLine(s: string = '') { 20 | this.push(s + '\n'); 21 | this.lines.push(this.indentString); 22 | } 23 | push(s: string) { 24 | let indentDelta = count(s, '{') - count(s, '}'); 25 | indentDelta += count(s, '(') - count(s, ')'); 26 | this.indent += indentDelta; 27 | if (indentDelta < 0) { 28 | if (this.lines.length > 0) { 29 | const lastLine = this.lines[this.lines.length-1].trim(); 30 | if (lastLine.length === 0) { 31 | this.lines.pop(); 32 | this.lines.push(this.indentString); 33 | } 34 | } 35 | } 36 | this.lines.push(s); 37 | } 38 | toString(): string { 39 | return this.lines.join(''); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /input/geometry-vector3.heron: -------------------------------------------------------------------------------- 1 | language heron:std:0.1; 2 | 3 | module heron:geometry.vector:0.1 4 | { 5 | // Several algorithms inspired by the following: 6 | // https://referencesource.microsoft.com/#System.Numerics/System/Numerics/Vector3 7 | // https://referencesource.microsoft.com/#System.Numerics/System/Numerics/Vector3_Intrinsics.cs 8 | 9 | // Variables 10 | 11 | var origin = vector(0, 0, 0); 12 | var ones = vector(1, 1, 1); 13 | var xaxis = vector(1, 0, 0); 14 | var yaxis = vector(0, 1, 0); 15 | var zaxis = vector(0, 0, 1); 16 | 17 | // Functions 18 | 19 | function vector(x: Float, y: Float, z: Float) 20 | = float3(x, y, z); 21 | 22 | function vector(x: Float) 23 | = vector(x, x, x); 24 | 25 | /* 26 | function vector(xs) 27 | = vector(xs[0], xs[1], xs[2]); 28 | */ 29 | 30 | function array(v) 31 | = [v.x, v.y, v.z]; 32 | 33 | function sumComponents(v) 34 | = v.x + v.y + v.z; 35 | 36 | function dot(a, b) 37 | = sumComponents(a * b); 38 | 39 | function length(v) 40 | = sqrt(v.length2); 41 | 42 | function length2(v) 43 | = v.dot(v); 44 | 45 | function distance(a, b) 46 | = (a - b).length; 47 | 48 | function distance2(a, b) 49 | = (a - b).length2; 50 | 51 | function normal(v) 52 | = v / v.length.vector; 53 | 54 | function cross(a, b) 55 | = vector(a.y*b.z - a.z*b.y, a.z*b.x - a.x*b.z, a.x*b.y - a.y*b.x); 56 | 57 | function reflect(v, n) 58 | = v - (n * dot(v, n) * 2.0); 59 | 60 | function lerp(a, b, x) 61 | = a * (1.0 - x) + b * x; 62 | 63 | function negate(v) 64 | = vector(-v.x, -v.y, -v.z); 65 | } -------------------------------------------------------------------------------- /source-browser/styles.css: -------------------------------------------------------------------------------- 1 | .code { 2 | background-color: #202020; 3 | white-space: pre; 4 | font-family: 'Inconsolata', 'Courier New', monospace; 5 | font-size: 14; 6 | color: white; 7 | padding: 10px; 8 | } 9 | .string { 10 | color: rosybrown; 11 | } 12 | .number { 13 | color: #f099bb; 14 | } 15 | .bool { 16 | color: #f099bb; 17 | } 18 | .fullComment, .lineComment { 19 | color: royalblue; 20 | font-style: italic; 21 | } 22 | .varName { 23 | color: goldenrod; 24 | } 25 | /* 26 | .langVer, .moduleName, .urn { 27 | color: darkgreen; 28 | } 29 | */ 30 | .keyword { 31 | color: #8aabfd; 32 | } 33 | .operator { 34 | color: #9497a2; 35 | } 36 | .funcName { 37 | color: white; 38 | } 39 | .funcParamName { 40 | color: #f2be3b; 41 | } 42 | .varNameDecl { 43 | color: #f2be3b; 44 | } 45 | .functionDef { 46 | position: relative; 47 | } 48 | .functionType { 49 | color: white; 50 | background-color: #333; 51 | opacity: 0.8; 52 | display: none; 53 | position: absolute; 54 | font-size: 0.8em; 55 | top: -1em; 56 | } 57 | .hideTypes .functionDef:hover > .functionType { 58 | display: inline-block; 59 | position: absolute; 60 | } 61 | .showTypes .functionType { 62 | display: inline-block; 63 | position: absolute; 64 | } 65 | .gitHubLink { 66 | position: fixed; 67 | left: 50%; 68 | top: 10px; 69 | transform: translateX(-50%); 70 | } 71 | .gitHubLink a { 72 | color: pink; 73 | } 74 | .button { 75 | position: fixed; 76 | right: 20; 77 | background-color: steelblue; 78 | border: none; 79 | color: white; 80 | text-align: center; 81 | text-decoration: none; 82 | padding: 15px; 83 | opacity: 0.8; 84 | } 85 | .button > a { 86 | color: black; 87 | } -------------------------------------------------------------------------------- /demo/sandbox/shaders.html: -------------------------------------------------------------------------------- 1 | 18 | 19 | 27 | 28 | 29 | 46 | 47 | -------------------------------------------------------------------------------- /src/type-parser.ts: -------------------------------------------------------------------------------- 1 | import { Type, typeConstant, typeVariable, polyType } from "./type-system"; 2 | import { Myna as m } from "myna-parser" 3 | 4 | // Defines syntax parsers for type expression, the lambda calculus, and Cat 5 | function registerGrammars() 6 | { 7 | // A simple grammar for parsing type expressions 8 | class TypeGrammar 9 | { 10 | typeExprRec = m.delay(() => this.typeExpr); 11 | typeList = m.guardedSeq('(', m.ws, this.typeExprRec.ws.zeroOrMore, ')').ast; 12 | typeVar = m.guardedSeq("'", m.identifier).ast; 13 | typeConstant = m.identifier.or(m.digits).or("->").or("*").or("[]").ast; 14 | typeExpr = m.choice(this.typeList, this.typeVar, this.typeConstant).ast; 15 | } 16 | const typeGrammar = new TypeGrammar(); 17 | m.registerGrammar('type', typeGrammar, typeGrammar.typeExpr); 18 | 19 | } 20 | 21 | registerGrammars(); 22 | 23 | export const typeParser = m.parsers['type']; 24 | 25 | export function parseType(input:string) : Type|null { 26 | var ast = typeParser(input); 27 | if (ast.end != input.length) 28 | throw new Error("Only part of input was consumed"); 29 | return astToType(ast); 30 | } 31 | 32 | function astToType(ast: any) : Type|null { 33 | if (!ast) 34 | return null; 35 | switch (ast.name) 36 | { 37 | case "typeVar": 38 | return typeVariable(ast.allText.substr(1)); 39 | case "typeConstant": 40 | return typeConstant(ast.allText); 41 | case "typeList": 42 | return polyType(ast.children.map(astToType)); 43 | case "typeExpr": 44 | if (ast.children.length != 1) 45 | throw new Error("Expected only one child of node, not " + ast.children.length); 46 | return astToType(ast.children[0]); 47 | default: 48 | throw new Error("Unrecognized type expression: " + ast.name); 49 | } 50 | } 51 | 52 | -------------------------------------------------------------------------------- /tools/gen-visitor.js: -------------------------------------------------------------------------------- 1 | // Variable usage 2 | // - Declaration 3 | // - Usage 4 | // - function calls 5 | 6 | const m = require("myna-parser"); 7 | const g = require('../build/heron-parser').heronGrammar; 8 | const grammarName = "heron"; 9 | 10 | function createAstVisitorFunction(rule, lines) { 11 | lines.push(" visit_" + rule.name + "(ast, state) {"); 12 | lines.push(" // " + rule.astRuleDefn()); 13 | lines.push(" this.visitChildren(ast, state);"); 14 | lines.push(" }") 15 | } 16 | 17 | function createCaseStatement(rule, lines) { 18 | lines.push(" case '" + rule.name + "': "); 19 | lines.push(" // " + rule.astRuleDefn()); 20 | lines.push(" ast['property'] = somevalue;"); 21 | lines.push(" break;") 22 | } 23 | 24 | function createAstVisitor() { 25 | var lines = [ 26 | "class " + grammarName + "Visitor", 27 | "{", 28 | " visitNode(ast, state) {", 29 | " const fnName = 'visit_' + ast.name;", 30 | " if (fnName in this)", 31 | " this[fnName](ast, state);", 32 | " else", 33 | " this.visitChildren(ast, state);", 34 | " }", 35 | " visitChildren(ast, state) {", 36 | " for (let child of ast.children)", 37 | " this.visitNode(child, state);", 38 | " }" 39 | ]; 40 | var rules = m.grammarAstRules(grammarName); 41 | for (var r of rules) 42 | createAstVisitorFunction(r, lines); 43 | lines.push("}"); 44 | 45 | return lines.join("\n"); 46 | } 47 | 48 | function createAstSwitch() { 49 | var lines = [ 50 | "switch (ast.name) {" 51 | ]; 52 | var rules = m.grammarAstRules(grammarName); 53 | for (var r of rules) 54 | createCaseStatement(r, lines); 55 | lines.push(' default:'); 56 | lines.push("}"); 57 | 58 | return lines.join("\n"); 59 | } 60 | 61 | //const output = createAstVisitor(); 62 | const output = createAstSwitch(); 63 | console.log(output); 64 | 65 | process.exit(); -------------------------------------------------------------------------------- /comparison.md: -------------------------------------------------------------------------------- 1 | ## Heron Compared to TypeScript / JavaScript 2 | 3 | Heron most closely resembles a subset of the JavaScript language. It has a type system that is more restricted than TypeScript, but the type-inference system is more aggressive. For example Heron function parameter types are inferred based on usage in the function defintion, as opposed to resolving to `any`. 4 | 5 | The biggest standout difference is that Heron has no concept of classes or prototypes. 6 | 7 | Heron is an unordered list of various differences Heron has with TypeScript/JavaScript: 8 | 9 | * only primitive types, generic types (including array and function), and type variables 10 | * no object literals 11 | * no `this` keyword 12 | * functions can be called using dot notation on the first argument 13 | * functions can be ovoverloaded (two functions can have the same name if the inferred types are different) 14 | * operators can be overloaded 15 | * operators can be passed as functions 16 | * `var` statements are equivalent to `let` statements in TypeScript/JavaScript 17 | * no `const` statements 18 | * module level variables cannot be modified 19 | * variable types are inferred 20 | * parameter and return types of functions are inferred 21 | * variables have to always be initialized 22 | * variable binding expression allows variable declarations to be used as expressions 23 | * arrays are immutable 24 | * modifying arrays can only be done with `ArrayBuilder` 25 | * each `ArrayBuilder` modification creates a new array 26 | * only supports a `for..in` loop form which is the same as `for..of` loop in JavaScript 27 | * a built-in range operator `from..to` generates an array of contiguous values (exclusive upper bound) 28 | * arrays do not necessarily allocate memory, e.g. 0..100000000, has O(1) memory consumption 29 | * module names are URN's with the version number encoded in it 30 | * all files specify the version of the language 31 | * all definitions must be in a module 32 | * variables cannot be reassigned to objects of a different type 33 | * no `async` or `await` support 34 | * no operators spread support 35 | * no class or interface definitions 36 | * anonymous functions use a *fat arrow* syntax 37 | * Separation betwen integers (`Int`) and floating point numbers (`Float`) 38 | * Support for two, three, and four dimensional numerical types like in GLSL (`Float2`, `Float3`, `Float4`). 39 | * Semicolons are required as statement terminators. 40 | * No statement labels 41 | * No comma operator 42 | * No switch statement 43 | -------------------------------------------------------------------------------- /input/sandbox/geometry-quaternion.heron: -------------------------------------------------------------------------------- 1 | language heron:std:0.1; 2 | 3 | // https://referencesource.microsoft.com/#System.Numerics/System/Numerics/Quaternion.cs 4 | // http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/index.htm 5 | // https://github.com/mrdoob/three.js/blob/master/src/math/Vector3.js 6 | 7 | module heron:geometry.quaternion:0.1 8 | { 9 | function quaternion(v) 10 | = float4(v.x, v.y, v.z, v.w); 11 | 12 | function quaternion(x, y, z, w) 13 | = float4(x, y, z, w); 14 | 15 | function quaternion(x, y, z) 16 | = quaternion(x, y, z, 1); 17 | 18 | function quaternion(v, w) 19 | = quaternion(v.x, v.y, v.z, w); 20 | 21 | var quaternion_identity 22 | = quaternion(0, 0, 0, 1); 23 | 24 | var quaternion_zero 25 | = quaternion(0, 0, 0, 0); 26 | 27 | function length2(q) 28 | = q.x * q.x + q.y * q.y + q.z * q.z + q.w * q.w; 29 | 30 | function length(q) 31 | = q.length2.sqrt; 32 | 33 | // http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToQuaternion/index.htm 34 | function quaternion(axis, angle) 35 | = quaternion( 36 | axis.x * sin(angle/2), 37 | axis.y * sin(angle/2), 38 | axis.z * sin(angle/2), 39 | cos(angle/2)); 40 | 41 | function quaternion() 42 | = quaternion(0, 0, 0, 0); 43 | 44 | function angle(q) 45 | = 2 * acos(q.w); 46 | 47 | // http://www.euclideanspace.com/maths/geometry/rotations/conversions/eulerToQuaternion/index.htm 48 | function quaternion(heading, attitude, bank) { 49 | var c1 = cos(heading / 2); 50 | var c2 = cos(attitude / 2); 51 | var c3 = cos(bank / 2); 52 | var s1 = sin(heading / 2); 53 | var s2 = sin(attitude / 2); 54 | var s3 = sin(bank / 2); 55 | return quaternion( 56 | s1 * s2 * c3 + c1 * c2 * s3 57 | s1 * c2 * c3 + c1 * s2 * s3 58 | c1 * s2 * c3 - s1 * c2 * s3 59 | c1 * c2 * c3 - s1 * s2 * s3); 60 | 61 | // http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToAngle/ 62 | function axis(q) 63 | = vector( 64 | q.x / sqrt(1-q.w*q.w), 65 | q.y / sqrt(1-q.w*q.w), 66 | q.z / sqrt(1-q.w*q.w)); 67 | 68 | function normal(q) = 69 | var invLen = 1.0f / q.length in 70 | quaternion(q.X * invLen, q.Y * invLen, q.Z * invLen, q.W * invLen); 71 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Heron 4 | 5 | 11 | 12 | 13 | 14 | 15 | Fork me on GitHub

Heron Language 3D Geometry Demo

16 | 17 |
18 |
19 |

20 | Heron is a new statically typed functional programming 21 | language with a JavaScript-like syntax that specializes in the processing of arrays of numerical data. 22 |

23 |

24 | This demo uses Heron to generate mesh data (vertices, faces, and colors) 25 | and uses Three.JS to display the resulting geometry. 26 | Browse the source code here: 27 |

33 |

34 |

35 | If you are interested in learning more, or collaborating please reach out to me, 36 | Christopher Diggins, via email 37 | LinkedIn, Twitter, 38 | or GitHub. 39 |

40 |
41 |
42 |