├── .gitignore ├── CushyLint ├── CushyLint ├── CushyLint.bat ├── CushyLint.pika ├── build │ ├── MakaronCmd │ ├── MakaronCmd.exe │ ├── PikaCmd │ └── PikaCmd.exe ├── cushy.schema ├── cushy.schema.pika ├── include │ ├── cushySchema.ppeg │ ├── initPPEG.pika │ ├── numbstrictMeta.ppeg │ ├── objects.pika │ └── systools.pika └── support │ ├── BuildCpp.cmd │ ├── BuildCpp.sh │ ├── Makaron.cpp │ ├── Makaron.h │ ├── MakaronCmd.cpp │ ├── buildMakaron.cmd │ └── buildMakaron.sh ├── IVGFontConverter └── IVGFontConverter.node.js ├── JSConsole.mtscript ├── JSConsole.js ├── JSConsole_main.cushy ├── JSConsole_main.js └── JSConsole_main.schema ├── README.md ├── docs ├── IVG Documentation.html ├── IVG Documentation.md ├── ImpD Documentation.html ├── ImpD Documentation.md ├── Makaron Documentation.html ├── Makaron Documentation.md ├── Microtonic JS Reference.html ├── Microtonic JS Reference.md └── images │ ├── colorsExample.png │ ├── contextDemo.png │ ├── curveQualityDemo.png │ ├── defineFontExample.png │ ├── ellipseExample.png │ ├── fillRuleDemo.png │ ├── gammaDemo.png │ ├── gradientDemo.png │ ├── imageExample.png │ ├── maskDemo.png │ ├── paintDemo.png │ ├── patternResolutionDemo.png │ ├── rectExample.png │ ├── smiley.png │ ├── starExample.png │ ├── strokesDemo.png │ ├── svgPathExample.png │ ├── textExample.png │ ├── transformDemo.png │ └── wipeExample.png ├── ivgfiddle ├── ace │ ├── ace.js │ ├── ext-searchbox.js │ ├── mode-ivg.js │ └── theme-twilight.js ├── ivgfiddle.html ├── ivgfiddle.js ├── rasterizeIVG.js └── setupModule.js ├── legacy ├── MicroTonic PikaScript Reference.html ├── MicroTonic PikaScript Reference.txt ├── PikaScript Documentation.html ├── PikaScript Documentation.txt ├── Prompt.pika ├── Test MRPikaEngine.pika └── help │ ├── arrays.html │ ├── containers.html │ ├── debug.html │ ├── debugging.html │ ├── help.html │ ├── index.html │ ├── math.html │ ├── objects.html │ ├── queues.html │ ├── strings.html │ ├── utilities.html │ └── utils.html └── tmLanguages └── soniccharge ├── .vscode └── launch.json ├── .vscodeignore ├── cushy.tmLanguage ├── cushyschema.tmLanguage ├── impd.tmLanguage ├── ivg.tmLanguage ├── ivgfont.tmLanguage ├── makaron.tmLanguage ├── package.json └── soniccharge.language-configuration.json /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | .DS_Store 3 | -------------------------------------------------------------------------------- /CushyLint/CushyLint: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | cd "$(dirname "$0")" 3 | ./build/PikaCmd ./CushyLint.pika "$@" 4 | -------------------------------------------------------------------------------- /CushyLint/CushyLint.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | CD /D "%~dp0" 3 | .\build\PikaCmd.exe .\CushyLint.pika %* 4 | -------------------------------------------------------------------------------- /CushyLint/build/MakaronCmd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malstrom72/microtonic-scripts-sdk/90d8465f350b939feb102718a0cee1a6a903a767/CushyLint/build/MakaronCmd -------------------------------------------------------------------------------- /CushyLint/build/MakaronCmd.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malstrom72/microtonic-scripts-sdk/90d8465f350b939feb102718a0cee1a6a903a767/CushyLint/build/MakaronCmd.exe -------------------------------------------------------------------------------- /CushyLint/build/PikaCmd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malstrom72/microtonic-scripts-sdk/90d8465f350b939feb102718a0cee1a6a903a767/CushyLint/build/PikaCmd -------------------------------------------------------------------------------- /CushyLint/build/PikaCmd.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malstrom72/microtonic-scripts-sdk/90d8465f350b939feb102718a0cee1a6a903a767/CushyLint/build/PikaCmd.exe -------------------------------------------------------------------------------- /CushyLint/include/cushySchema.ppeg: -------------------------------------------------------------------------------- 1 | # KVSequence = [ 2 | # { kind: 'kv', key: string, value: Value } 3 | # | { kind: 'opt', seq: KVSequence } 4 | # | { kind: 'alts', seqs: [ KVSequence, ... ] } 5 | # ... 6 | # [ { kind: 'unmatched', template: Value } ] // unmatched keys must match (can only be one, no 'unmatched' = no unmatched keys allowed) ] 7 | # ] 8 | # 9 | # Value = 10 | # { kind: 'struct', seq: KVSequence } // numbstrict type must be struct 11 | # | { kind: 'array', template: Value } // numbstrict type must be array (0 or more matches) 12 | # | { kind: 'list', values: [ Value, ... ] } // numbstrict type must be array (exact length or less if last items are optional) 13 | # | { kind: 'rule', name: string } 14 | # | { kind: 'literal', type: text|string, literal: string } // numbstrict type must be text or string 15 | # | { kind: 'peg', type: text|string, peg: peg|void } // numbstrict type must be text or string, void peg = match any 16 | # | { kind: 'string', peg: peg|void } // numbstrict type must be string, void = match any 17 | # | { kind: 'opt', value: Value } 18 | # | { kind: 'alts', values: [ Value, ... ] } 19 | # | { kind: 'any' } // anything goes! 20 | # | { kind: 'func', func: string, arg: string } // validate against special validator function 'func' with argument 'arg' 21 | # | { kind: 'tag', group: string, tag: string } // collect value and check against group rule 22 | 23 | 24 | 25 | { 26 | $$parser.fail = function { 27 | args(@message, @$offset); 28 | throw(bake('({$offset}) {message}')) 29 | }; 30 | $$parser.define = >{ // access to $$parser requires > type function when compiling parser as a single function 31 | args(@$container, @$label, @$definition, @$offset, @$error); 32 | if (exists(r = @[[$$parser.schema][$container]][$label])) $$parser.fail(bake($error), $offset); 33 | [r] = $definition; 34 | }; 35 | $$parser.addRef = >{ 36 | $ref = new(Container, 'kind', $0, 'name', $1, 'at', $2); 37 | if (exists($r = @[$$parser.schema].filename)) [$ref].fn = [$r]; 38 | append([$$parser.schema].refs, $ref) 39 | } 40 | } 41 | 42 | root <- { $$parser.schema = $$ } 43 | _lf definitions_ !. { $$ = $$parser.schema } 44 | 45 | definitions_ <- ( (definition_ (next_ definition_)* _lf 46 | / pegDefinition+ _lf 47 | / configLine_+) { gc() } 48 | ) * 49 | 50 | definition_ <- { $offset = $$i } 51 | l:label _lf '=' _lf d:valueSeq_ { $$parser.define('rules', $l, $d, $$i, 'Duplicate rule: <{$label}>') } 52 | 53 | configLine_ <- { $offset = $$i } 54 | k=identifier _ ':' _ v=((![\r\n] . )*) _lf { [$$parser.schema].configure($k, $v, $offset) } 55 | 56 | valueSeq_ <- value_ (_lf '|' _lf v:value_ { if ([$$].kind !== 'alts') $$ = new(Container, 'kind', 'alts', 'values', new(Array, $$)); append([$$].values, $v) } 57 | )* 58 | 59 | value_ <- (valueGroup / valueOptional / array / list 60 | / struct / rule / literal / peg / func / any 61 | / tag) _ 62 | 63 | valueGroup <- '(' _lf valueSeq_ _lf ')' 64 | valueOptional <- '[' _lf valueSeq_ _lf ']' { $$ = new(Container, 'kind', 'opt', 'value', $$) } 65 | 66 | rule <- { $offset = $$i } 67 | l:label _ { 68 | $$ = new(Container, 'kind', 'rule', 'name', $l); 69 | $$parser.addRef('rule', $l, $offset) 70 | } 71 | 72 | literal <- s=('"' ( escapeCode / !["\\\r\n] . )* '"' { $t = 'string' } 73 | / "'" ( escapeCode / !['\\\r\n] . )* "'" { $t = 'text' } 74 | ) { $$ = new(Container, 'kind', 'literal', 'type', $t, 'literal', unescape($s)) } 75 | 76 | peg <- { $offset = $$i; $id = void } 77 | t=[%*] id=identifier? _ { 78 | $t = (if ($t === '%') 'string' else 'text'); 79 | $$ = new(Container, 'kind', 'peg', 'type', $t, 'peg', $id); 80 | if ($id != void) $$parser.addRef('peg', $id, $offset) 81 | } 82 | 83 | tag <- { $offset = $$i } 84 | '\\' g=identifier '\\' t=identifier { 85 | $$ = new(Container, 'kind', 'tag', 'group', $g, 'tag', $t); 86 | $$parser.addRef('rule', $g, $offset) 87 | } 88 | 89 | func <- { $offset = $$i } 90 | '?' f=identifier (':' _ a:funcArg)? { 91 | $$ = new(Container, 'kind', 'func', 'func', $f, 'arg', $a); 92 | $$parser.addRef('func', $f, $offset) 93 | } 94 | 95 | funcArg <- $$=('"' ( escapeCode / !["\\\r\n] . )* '"' 96 | / "'" ( escapeCode / !['\\\r\n] . )* "'" 97 | ) { $$ = unescape($$) } 98 | / $$=identifier 99 | 100 | any <- '?' _ { $$ = new(Container, 'kind', 'any') } 101 | 102 | array <- '{' _lf valueSeq_ next_ '...' _lf '}' { $$ = new(Container, 'kind', 'array', 'template', $$) } 103 | list <- '{' _lf valueSeq_ { $$ = new(Container, 'kind', 'list', 'values', new(Array, $$)) } 104 | (next_ v:valueSeq_ { append([$$].values, $v); } 105 | )* _lf '}' 106 | 107 | struct <- '{' _lf { $$ = new(Array) } 108 | ((unmatched 109 | / kvList_ (next_ unmatched)?) 110 | ) _lf '}' { $$ = new(Container, 'kind', 'struct', 'seq', $$) } 111 | 112 | kvList_ <- kvSeq_ (next_ kvSeq_)* 113 | 114 | kvSeq_ <- { $alts = new(Array); $kv = new(Array) } 115 | kv:kvElem_ { append($alts, $kv) } 116 | (_lf '|' _lf { $kv = new(Array) } 117 | kv:kvElem_ { append($alts, $kv) } 118 | )* { 119 | if ([$alts].n == 1) inject([$alts][0], 0, [[$alts][0]].n, $$, [$$].n) 120 | else append($$, new(Container, 'kind', 'alts', 'seqs', $alts)) 121 | } 122 | kvElem_ <- kvGroup_ / kvOptional_ / keyValue_ 123 | 124 | kvGroup_ <- '(' _lf kvList_ _lf ')' _ 125 | kvOptional_ <- '[' _lf { $kv = new(Array) } 126 | kv:kvList_ _lf ']' _ { append($$, new(Container, 'kind', 'opt', 'seq', $kv)) } 127 | keyValue_ <- k=identifier _ ':' _lf v:valueSeq_ { append($$, new(Container, 'kind', 'kv', 'key', $k, 'value', $v)) } 128 | 129 | unmatched <- '*' _ ':' _lf v:valueSeq_ _ { append($$, new(Container, 'kind', 'unmatched', 'template', $v)) } 130 | 131 | label <- '<' $$=identifier '>' 132 | 133 | next_ <- (["\r\n"] (_lf ',')? / _lf ',') _lf 134 | 135 | identifier <- [a-zA-Z0-9_]+ 136 | 137 | _lf <- (comment / [ \t\r\n])* 138 | _ <- (comment / [ \t])* 139 | 140 | comment <- singleLineComment / multiLineComment 141 | singleLineComment <- '//' (![\r\n] .)* 142 | multiLineComment <- '/*' (multiLineComment / !'*/' .)* '*/' 143 | 144 | escapeCode <- '\\x' hex2 / '\\u' hex4 / '\\l' hex8 / '\\' [0-9]+ / '\\' [nrt'"\\] 145 | hex8 <- hex4 hex4 146 | hex4 <- hex2 hex2 147 | hex2 <- hex hex 148 | hex <- [0-9A-Fa-f] 149 | 150 | 151 | 152 | ########### 153 | # # 154 | # PEG # 155 | # # 156 | ########### 157 | 158 | pegDefinition <- id:pegIdentifier LEFTARROW x=pegExpression { $$parser.define('pegs', $id, $x, $$i, 'Duplicate peg: {$label}') } 159 | pegExpression <- pegSequence (SLASH pegSequence)* 160 | pegSequence <- pegPrefix* 161 | pegPrefix <- (AND / NOT)? pegSuffix 162 | pegSuffix <- pegPrimary (QUESTION / STAR / PLUS)? 163 | pegPrimary <- pegIdentifier !LEFTARROW 164 | / OPEN pegExpression CLOSE 165 | / pegLiteral / pegClass / DOT 166 | 167 | # Lexical syntax 168 | pegIdentifier <- $$=(pegIdentStart pegIdentCont*) pegSpacing 169 | pegIdentStart <- [a-zA-Z_] 170 | pegIdentCont <- pegIdentStart / [0-9] 171 | 172 | pegLiteral <- ['] (!['] pegChar)* ['] pegSpacing 173 | / ["] (!["] pegChar)* ["] pegSpacing 174 | pegClass <- '[' (!']' pegRange)* ']' pegSpacing 175 | pegRange <- pegChar '-' pegChar / pegChar 176 | pegChar <- '\\' [nrt'"\[\]\\] 177 | / '\\' [0-2][0-7][0-7] # ML 20100501 : this can't be right, \277 is 191, must have meant [0-3][0-7][0-7] 178 | / '\\' [0-7][0-7]? 179 | / !'\\' . 180 | 181 | LEFTARROW <- '<-' pegSpacing 182 | SLASH <- '/' pegSpacing 183 | AND <- '&' pegSpacing 184 | NOT <- '!' pegSpacing 185 | QUESTION <- '?' pegSpacing 186 | STAR <- '*' pegSpacing 187 | PLUS <- '+' pegSpacing 188 | OPEN <- '(' pegSpacing 189 | CLOSE <- ')' pegSpacing 190 | DOT <- '.' pegSpacing 191 | 192 | pegSpacing <- (pegSpace / pegComment)* 193 | pegComment <- '#' (!pegEndOfLine .)* pegEndOfLine 194 | pegSpace <- ' ' / '\t' / pegEndOfLine 195 | pegEndOfLine <- !([\r\n] [ \t\r\n]* ('<' / '/*')) ('\r\n' / '\n' / '\r') 196 | -------------------------------------------------------------------------------- /CushyLint/include/numbstrictMeta.ppeg: -------------------------------------------------------------------------------- 1 | # diff from loose numbstruck: 2 | # 3 | # . ctrl-z eof is not recognized 4 | # . valid space characters are [ \t\r\n] (ascii codes 32, 7, 13 and 10) 5 | # . valid characters in comments are space characters and ascii codes 33 to 255 6 | # . valid characters for unquoted keys are [a-zA-Z0-9_] (first must not be a digit) 7 | # . valid characters in unquoted text are [ \t] and ascii codes 33 to 126 except [{}"':,=;] 8 | # . valid characters in quoted strings are [ ] and ascii codes 33 to 126 9 | # . recognized escape sequences are: '\x' '\u' '\U' '\n' '\r' '\t' '\'' '\"' '\\' 10 | # . '\l' escape sequence (for 32-bit characters) has been replaced with '\U' 11 | # . '\x' '\u' and '\U' must have exact number of hex digits (2, 4 and 8) 12 | # . no escape sequence for decimal character codes 13 | # . [=] is not accepted as key/value separator, only [:] (and it is required) 14 | # . [:] after key must be on the same line (also for quoted keys) 15 | # . [,] or [\n] (or both) is required between each element 16 | # . [;] is not accepted as element separator, only [,] or [\n] 17 | # . trailing [,] in key/value lists is illegal (but ok in value only lists) 18 | # . '{ : }' may be used to declare an empty struct (to differentiate from an empty array) 19 | 20 | # Meta output: 21 | # { 22 | # ( type: 'struct', value: Container ) 23 | # | ( type: 'array', value: Array ) 24 | # | ( type: 'string'|'text' value: ) 25 | # | void // for empty slots in arrays 26 | # begin: 27 | # end: 28 | # } 29 | 30 | { 31 | $$parser.fail = function { args(@message, @offset); throw(bake('({offset}) {message}')) }; 32 | $$parser.Meta = function { map(this(), 'type', $0, /*'source', $1{$2:$3-$2},*/ 'begin', $2, 'end', $3, 'value', $4) } 33 | } 34 | 35 | root <- _lf { $b = $$i; $$ = new(Container) } 36 | keyValueList_? { $$ = new($$parser.Meta, 'struct', $$s, $b, $$i, $$) } 37 | !. 38 | 39 | valueList_ <- 40 | (v:value _ next_ { append($$, $v) } 41 | / ',' { append($$, void) } 42 | _lf)* 43 | (v:value _lf { append($$, $v) } 44 | )? 45 | 46 | keyValueList_ <- (':' / keyValue_ (next_ keyValue_)*) _lf 47 | 48 | next_ <- ([\r\n] (_lf ',')? / _lf ',') _lf 49 | 50 | keyValue_ <- { $b = $$i } 51 | k:key { $v = void } 52 | (_ ':' _ v:value? { if ($v === void) $v = new($$parser.Meta, 'text', $$s, $$i, $$i, ''); } 53 | ) _ { 54 | if (exists(@[$$][$k])) $$parser.fail(bake('Duplicate key: {escape($k)}'), $b); 55 | [$$][$k] = $v 56 | } 57 | 58 | key <- quotedString / identifier 59 | value <- array / struct / string / text 60 | 61 | array <- { $b = $$i } 62 | '{' { $$ = new(Array) } 63 | _lf valueList_ '}' { $$ = new($$parser.Meta, 'array', $$s, $b, $$i, $$) } 64 | 65 | struct <- { $b = $$i } 66 | '{' { $$ = new(Container) } 67 | _lf keyValueList_ '}' { $$ = new($$parser.Meta, 'struct', $$s, $b, $$i, $$) } 68 | 69 | string <- { $b = $$i } 70 | quotedString { $$ = new($$parser.Meta, 'string', $$s, $b, $$i, $$) } 71 | 72 | text <- { $$ = ''; $b = $$i } 73 | (_ s=(![{}"':,=;] !'/*' !'//' [\41-\176])+ { $$ #= (if ($$ !== '') ' ') # $s } 74 | )+ { $$ = new($$parser.Meta, 'text', $$s, $b, $$i, $$) } 75 | 76 | quotedString <- $$=('"' ( escapeCode / !["\\] [\40-\176])* '"' 77 | / "'" ( escapeCode / !['\\] [\40-\176])* "'") { $$ = unescape($$) /* sorry, but no \u or \U supported here */ } 78 | 79 | identifier <- $$=([a-zA-Z_] [a-zA-Z0-9_]*) 80 | 81 | _lf <- (comment / [ \t\r\n])* 82 | _ <- (comment / [ \t])* 83 | 84 | comment <- singleLineComment / multiLineComment 85 | singleLineComment <- '//' [\40-\377\t]* (!. / &[\r\n]) 86 | multiLineComment <- '/*' (multiLineComment / !'*/' [\40-\377\t\r\n])* '*/' 87 | 88 | escapeCode <- '\\x' hex2 / '\\u' hex4 / '\\U' hex8 / '\\' [nrt'"\\] 89 | hex8 <- hex4 hex4 90 | hex4 <- hex2 hex2 91 | hex2 <- hex hex 92 | hex <- [0-9A-Fa-f] 93 | -------------------------------------------------------------------------------- /CushyLint/include/objects.pika: -------------------------------------------------------------------------------- 1 | 2 | // TODO : add Queue 3 | 4 | Array = function { this = this(); [this].n = $n; for (i = 0; i < $n; ++i) if (exists(@$[i])) [this][i] = $[i] }; 5 | Clone = function { this = this(); if (exists(@[$0].clone)) [$0].clone(this) else clone($0, this) }; 6 | Container = function { this = this(); for (i = 0; i + 2 <= $n; i += 2) [this][$[i]] = $[i + 1] }; 7 | Map = function { 8 | this = this(); 9 | construct(this, Set); 10 | for (i = 0; i + 2 <= $n; i += 2) [this].elements[$[i]] = $[i + 1]; 11 | delete(@[this].add); 12 | map(this 13 | , 'get',function { [this()].elements[$0] } 14 | , 'set',function { [this()].elements[$0] = $1 }); 15 | }; 16 | Set = function { 17 | this = this(); 18 | for (i = 0; i < $n; ++i) [this].elements[$[i]] = true; 19 | map(this 20 | , 'add',function { [this()].elements[$0] = true } 21 | , 'contains',function { exists(@[this()].elements[$0]) } 22 | , 'foreach',function { foreach(@[this()].elements, $0) } 23 | , 'remove',function { delete(@[this()].elements[$0]) }); 24 | }; 25 | Value = function { this = this(); [this] = $0 }; 26 | Vector = function { 27 | this = this(); 28 | for (i = 0; i < $n; ++i) if (exists(@$[i])) [this].elements[i] = $[i]; 29 | [this].elements.n = $n; 30 | map(this 31 | , 'append',function { e = @[this()].elements; inject(@$, 0, $n, e, [e].n) } 32 | , 'contains',function { ($0 >= 0 && $0 < [this()].elements.n) } 33 | , 'copy',function { copy(@[$0].elements, $1, $2, @[this()].elements, $3) } 34 | , 'decompose',function { this = this(); for (i = 0; i < $n; ++i) if (exists(@$[i])) [$[i]] = [this].elements[i] } 35 | , 'equal',function { equal(@[this()].elements, @[$0].elements) } 36 | , 'fill',function { fill(@[this()].elements, $0, $1, $2) } 37 | , 'foreach',function { iterate(@[this()].elements, $0) } 38 | , 'get',function { [this()].elements[$0] } 39 | , 'insert',function { inject(@$, 1, $n - 1, @[this()].elements, $0) } 40 | , 'remove',function { remove(@[this()].elements, $0, coalesce(@$1, 1)) } 41 | , 'rsort',function { rsort(@[this()].elements) } 42 | , 'set',function { e = @[this()].elements; [e][~~$0] = $1; [e].n = max([e].n, $0 + 1) } 43 | , 'size',function { [this()].elements.n } 44 | , 'sort',function { sort(@[this()].elements) }); 45 | }; 46 | deepDump = function { 47 | vargs(, @var, @indent, @indentString, @maxDepth, @useCustomToSource); 48 | defaults(@var, @^, @indent, 0, @indentString, "\t", @maxDepth, 20, @useCustomToSource, false); 49 | 50 | customToSource = function { 51 | if ((c = classify($0)) === 'void') ( c ) 52 | else if (c === 'string' || c === 'function') ( escape($0) ) 53 | else if (c === 'reference') if ($0{0:2} === '::') ( '@' # $0 ) else ( escape($0) ) 54 | else ( $0 ) 55 | }; 56 | 57 | stringify = (if (useCustomToSource) customToSource else toSource); 58 | output = >{ print(repeat(indentString, $0) # limitLength(singleLine($1), CONSOLE_COLS - length(var) - 3)) }; 59 | printOne = >{ 60 | output($0, $1 # ' = ' # stringify($2)); 61 | if (classify($2) === 'reference') deepDump($2, $0 + 1, indentString, maxDepth, useCustomToSource); 62 | }; 63 | if (indent >= maxDepth) output(indent, '!!!! TOO DEEP') 64 | else { 65 | if (exists(var)) printOne(indent, var, [var]); 66 | foreach(var, >printOne(indent, $1, $2)) 67 | }; 68 | ( void ) 69 | }; 70 | 71 | void; 72 | -------------------------------------------------------------------------------- /CushyLint/support/BuildCpp.cmd: -------------------------------------------------------------------------------- 1 | @SETLOCAL ENABLEEXTENSIONS ENABLEDELAYEDEXPANSION 2 | @IF NOT EXIST "%SC_ROOT%" ( ECHO ERROR: SC_ROOT environment variable not correctly set. & EXIT /B 1 ) 3 | @CALL %SC_ROOT%Tools\bin\SelectMSVC.cmd || EXIT /B 1 4 | 5 | 6 | IF "%CPP_TARGET%"=="" SET CPP_TARGET=release 7 | IF "%CPP_MODEL%"=="" SET CPP_MODEL=64 8 | 9 | IF "%~1"=="debug" ( 10 | SET CPP_TARGET=debug 11 | SHIFT 12 | ) ELSE IF "%~1"=="beta" ( 13 | SET CPP_TARGET=beta 14 | SHIFT 15 | ) ELSE IF "%~1"=="release" ( 16 | SET CPP_TARGET=release 17 | SHIFT 18 | ) 19 | 20 | IF "%~1"=="32" ( 21 | SET CPP_MODEL=32 22 | SHIFT 23 | ) ELSE IF "%~1"=="64" ( 24 | SET CPP_MODEL=64 25 | SHIFT 26 | ) 27 | 28 | IF "%CPP_TARGET%"=="debug" ( 29 | SET CPP_OPTIONS=/Od /MTd /GS /Zi /D DEBUG %CPP_OPTIONS% 30 | ) ELSE IF "%CPP_TARGET%"=="beta" ( 31 | SET CPP_OPTIONS=/O2 /GL /MTd /GS /Zi /D DEBUG %CPP_OPTIONS% 32 | ) ELSE IF "%CPP_TARGET%"=="release" ( 33 | SET CPP_OPTIONS=/O2 /GL /MT /GS- /D NDEBUG %CPP_OPTIONS% 34 | ) ELSE ( 35 | ECHO Unrecognized CPP_TARGET %CPP_TARGET% 36 | EXIT /B 1 37 | ) 38 | 39 | IF "%CPP_MODEL%"=="64" ( 40 | SET vcvarsConfig=x86_amd64 41 | ) ELSE IF "%CPP_MODEL%"=="32" ( 42 | SET CPP_OPTIONS=/arch:SSE2 %CPP_OPTIONS% 43 | SET vcvarsConfig=x86 44 | ) ELSE ( 45 | ECHO Unrecognized CPP_MODEL %CPP_MODEL% 46 | EXIT /B 1 47 | ) 48 | 49 | SET args=%1 50 | SET name=%~n1 51 | SHIFT 52 | 53 | SET CPP_OPTIONS=/W3 /EHsc /D "WIN32" /D "_CONSOLE" /D "_CRT_SECURE_NO_WARNINGS" /D "_SCL_SECURE_NO_WARNINGS" %CPP_OPTIONS% 54 | 55 | IF "%name%"=="" ( 56 | ECHO BuildCpp [debug^|beta^|release] [32^|64 ^(bit^)] ^ ^ 57 | ECHO You can also use the environment variables: CPP_MSVC_VERSION, CPP_TARGET, CPP_MODEL and CPP_OPTIONS 58 | EXIT /B 1 59 | ) 60 | 61 | :argLoop 62 | IF "%~1"=="" goto argLoopEnd 63 | SET "args=%args% %1" 64 | SHIFT 65 | goto argLoop 66 | :argLoopEnd 67 | 68 | 69 | SET temppath=%TEMP:"=%\%name%_%RANDOM% 70 | MKDIR "%temppath%" >NUL 2>&1 71 | ECHO Compiling %name% %CPP_TARGET% %CPP_MODEL% using MSVC V%CPP_MSVC_VERSION% 72 | ECHO %CPP_OPTIONS% /Fe%args% 73 | ECHO. 74 | cl %CPP_OPTIONS% /errorReport:queue /Fo"%temppath%\\" /Fe%args% >"%temppath%\buildlog.txt" 75 | IF ERRORLEVEL 1 ( 76 | TYPE "%temppath%\buildlog.txt" 77 | ECHO Compilation of %name% failed 78 | DEL /Q "%temppath%\*" >NUL 2>&1 79 | RMDIR /Q "%temppath%" >NUL 2>&1 80 | EXIT /B 1 81 | ) ELSE ( 82 | ECHO Compiled %name% 83 | DEL /Q "%temppath%\*" >NUL 2>&1 84 | RMDIR /Q "%temppath%\" >NUL 2>&1 85 | 86 | EXIT /B 0 87 | ) 88 | -------------------------------------------------------------------------------- /CushyLint/support/BuildCpp.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | CPP_COMPILER="${CPP_COMPILER-g++}" 4 | CPP_OPTIONS="${CPP_OPTIONS-}" 5 | CPP_TARGET="${CPP_TARGET-release}" 6 | CPP_MODEL="${CPP_MODEL-64}" 7 | 8 | if [ "$1" == "debug" ] || [ "$1" == "beta" ] || [ "$1" == "release" ]; then 9 | CPP_TARGET="$1" 10 | shift 11 | fi 12 | 13 | if [ "$1" == "64" ] || [ "$1" == "32" ]; then 14 | CPP_MODEL="$1" 15 | shift 16 | fi 17 | 18 | if [ "$CPP_TARGET" == "debug" ]; then 19 | CPP_OPTIONS="-O0 -DDEBUG -g $CPP_OPTIONS" 20 | elif [ "$CPP_TARGET" == "beta" ]; then 21 | CPP_OPTIONS="-Os -DDEBUG -g $CPP_OPTIONS" 22 | elif [ "$CPP_TARGET" == "release" ]; then 23 | CPP_OPTIONS="-Os -DNDEBUG $CPP_OPTIONS" 24 | else 25 | echo Unrecognized CPP_TARGET "$CPP_TARGET" 26 | exit 1 27 | fi 28 | 29 | if [ "$CPP_MODEL" == "64" ]; then 30 | CPP_OPTIONS="-m64 $CPP_OPTIONS" 31 | elif [ "$CPP_MODEL" == "32" ]; then 32 | CPP_OPTIONS="-m32 $CPP_OPTIONS" 33 | else 34 | echo Unrecognized CPP_MODEL "$CPP_MODEL" 35 | exit 1 36 | fi 37 | 38 | CPP_OPTIONS="-fvisibility=hidden -fvisibility-inlines-hidden -Wno-trigraphs -Wreturn-type -Wunused-variable $CPP_OPTIONS" 39 | 40 | if [ $# -lt 2 ]; then 41 | echo "BuildCpp.sh [debug|beta|release*] [32|64* (bit)] " 42 | echo "You can also use the environment variables: CPP_COMPILER, CPP_TARGET, CPP_MODEL and CPP_OPTIONS" 43 | exit 1 44 | fi 45 | 46 | echo Compiling $1 $CPP_TARGET $CPP_MODEL using $CPP_COMPILER 47 | echo $CPP_OPTIONS -o $@ 48 | logfile=$(mktemp) 49 | $CPP_COMPILER -pipe $CPP_OPTIONS -o $@ >"$logfile" 2>&1 50 | if [ $? -ne 0 ]; then 51 | cat "$logfile" 52 | rm "$logfile" 53 | echo Compilation of $1 failed 54 | exit 1 55 | else 56 | rm "$logfile" 57 | echo Compiled $1 58 | exit 0 59 | fi 60 | -------------------------------------------------------------------------------- /CushyLint/support/Makaron.h: -------------------------------------------------------------------------------- 1 | #ifndef Makaron_h 2 | #define Makaron_h 3 | 4 | #include "assert.h" // Note: I always include assert.h like this so that you can override it with a "local" file. 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | namespace Makaron { 13 | 14 | const int DEFAULT_RECURSION_DEPTH_LIMIT = 20; 15 | 16 | typedef char Char; 17 | typedef std::basic_string String; 18 | typedef String::const_iterator StringIt; 19 | 20 | class Exception : public std::exception { 21 | public: Exception(const std::string& error, const std::string& file, size_t offset, int line, int column) 22 | : error(error), file(file), offset(offset), line(line), column(column) { } 23 | std::string getError() const { return error; } 24 | std::string getFile() const { return file; } 25 | size_t getOffset() const { return offset; } // To get recursive source ranges, use the length of the generated output with findInputRanges instead. 26 | int getLineNumber() const { return line; } 27 | int getColumnNumber() const { return column; } 28 | virtual const char* what() const throw(); 29 | virtual ~Exception() throw() { } 30 | 31 | protected: const std::string error; 32 | const std::string file; 33 | const size_t offset; 34 | const int line; 35 | const int column; 36 | mutable std::string errorWithLine; 37 | }; 38 | 39 | class Span { 40 | friend class Context; 41 | public: Span(const String& sourceCode, const String& fileName); 42 | Span(const Span& s, const StringIt& b, const StringIt& e) : source(s.source), file(s.file) 43 | , begin(b), end(e) { 44 | assert(begin >= source->begin() && end <= source->end()); 45 | } 46 | operator String() const { return String(begin, end); } 47 | operator String() { return String(begin, end); } 48 | size_t sourceOffset(const StringIt& p) { return p - source->begin(); } 49 | 50 | protected: Span() { } 51 | std::shared_ptr source; 52 | std::shared_ptr file; 53 | StringIt begin; 54 | StringIt end; 55 | }; 56 | 57 | /** 58 | It is ok for a stretch from `outputPoint` to (`outputPoint`+`outputStretch`) to go one character past the generated 59 | output length. This means an error occured during output generation when processing this entry's input range. 60 | This entry should be included in the error diagnostics. 61 | 62 | If `inputLength` == 0 for passed text: inputOffset = inputFrom + (outputPoint - outputPoint) 63 | If `inputLength` > 0 for macro invokation: inputRange = inputFrom .. inputFrom + inputLength 64 | 65 | Generated offset map vectors will always be sorted by `outputPoint` ascending. With overlapping entries, the 66 | earliest element is the "outermost" (e.g. the first macro call) and the last element is the "innermost". 67 | */ 68 | struct OffsetMapEntry { 69 | std::shared_ptr file; 70 | size_t outputPoint; 71 | size_t outputStretch; 72 | size_t inputFrom; 73 | size_t inputLength; 74 | }; 75 | 76 | class Context { 77 | protected: struct Macro { 78 | std::vector params; 79 | Span span; 80 | Context* context; 81 | }; 82 | 83 | public: typedef std::function LoaderFunction; 84 | 85 | Context(int depthLimiter = DEFAULT_RECURSION_DEPTH_LIMIT, Context* parentContext = 0); 86 | bool defineMacro(const String& name, const std::vector& parameterNames, const Span& span, Context* context); 87 | bool defineString(const String& name, const String& definiton); 88 | bool redefineString(const String& name, const String& definiton); 89 | void process(const Span& input, String& output, std::vector* offsetMap); 90 | void setIncludeLoader(const LoaderFunction& loaderFunction); 91 | 92 | protected: static bool isWhite(const Char c); 93 | static bool isLeadingIdentifierChar(const Char c); 94 | static bool isIdentifierChar(const Char c); 95 | void error(const std::string error); 96 | bool eof() const; 97 | void skipWhite(); 98 | void skipHorizontalWhite(); 99 | void optionalLineBreak(); 100 | void skipBracketsAndStrings(int depth); 101 | bool parseToken(const char* token); 102 | String parseIdentifier(); 103 | String parseSymbol(); 104 | StringIt skipNested(const char* open, const char* close, bool skipLeadingWhite); 105 | Span parseNested(const char* open, const char* close, bool skipLeadingWhite); 106 | String parseExpression(const char* terminators); 107 | void parseArgumentList(std::vector& arguments); 108 | void parseParameterNames(std::vector& parameterNames); 109 | void stringDefinition(bool redefine); 110 | void macroDefinition(); 111 | bool testCondition(); 112 | void ifStatement(); 113 | void invokeMacro(); 114 | void includeFile(); 115 | void produce(const StringIt& b, const StringIt& e); 116 | 117 | Context* const parentContext; 118 | int depthLimiter; 119 | LoaderFunction loader; 120 | std::map macros; 121 | std::map strings; 122 | Span processing; 123 | String* processed; 124 | std::vector* offsets; 125 | StringIt p; 126 | }; 127 | 128 | // FIX : RangeVector should include file name too 129 | typedef std::vector< std::pair > RangeVector; 130 | 131 | /** 132 | Returns ranges in input text as absolute [begin, end) offsets for an offset in output text. In case of macro calls, 133 | first range returned is outermost and last is innermost. 134 | 135 | Notice that you can use this routine when an error occurs to get a full "call stack" of source ranges. Just pass the 136 | length of the generated output to `outputOffset`. 137 | */ 138 | RangeVector findInputRanges(const std::vector& offsetMap, size_t outputOffset); 139 | 140 | std::pair calculateLineAndColumn(const String& text, size_t offset); 141 | String process(const String& source, const String& fileName); 142 | bool unitTest(); 143 | 144 | } // namespace Makaron 145 | 146 | #endif 147 | -------------------------------------------------------------------------------- /CushyLint/support/MakaronCmd.cpp: -------------------------------------------------------------------------------- 1 | // FUTURE : allow multiple input files, but we need Span to also keep track of which file it is so we get proper error messages and also the map output file needs to include filenames 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "Makaron.h" 11 | 12 | #ifdef _WIN32 13 | const char SEPARATOR_CHARACTER = '\\'; 14 | #else 15 | const char SEPARATOR_CHARACTER = '/'; 16 | #endif 17 | 18 | std::vector includePaths; 19 | 20 | static std::string loadEntireStream(std::istream& stream) { 21 | std::istreambuf_iterator it(stream); 22 | std::istreambuf_iterator end; 23 | return std::string(it, end); 24 | } 25 | 26 | static bool myIncludeLoader(const Makaron::String& fileName, Makaron::String& contents) { 27 | for (std::vector::const_iterator it = includePaths.begin(); it != includePaths.end(); ++it) { 28 | std::ifstream fileStream(*it + fileName); 29 | if (fileStream.good()) { 30 | fileStream.exceptions(std::ios_base::badbit | std::ios_base::failbit); 31 | contents = loadEntireStream(fileStream); 32 | return true; 33 | } else if (!fileName.empty() && fileName.front() == SEPARATOR_CHARACTER) { // only use empty path if leading / 34 | assert(it->empty()); 35 | return false; 36 | } 37 | } 38 | return false; 39 | } 40 | 41 | 42 | #ifdef LIBFUZZ 43 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { 44 | std::vector offsetMap; 45 | Makaron::String processed; 46 | try { 47 | Makaron::String source = Makaron::String(reinterpret_cast(Data) 48 | , reinterpret_cast(Data) + Size); 49 | Makaron::Context context; 50 | context.process(source, processed, &offsetMap); 51 | } 52 | catch (const Makaron::Exception& x) { 53 | Makaron::RangeVector inputRanges = findInputRanges(offsetMap, processed.size()); 54 | } 55 | return 0; 56 | } 57 | #endif 58 | 59 | #ifndef LIBFUZZ 60 | int main(int argc, const char* argv[]) { 61 | assert(Makaron::unitTest()); 62 | 63 | int rc = 0; 64 | try { 65 | includePaths.push_back(std::string()); 66 | Makaron::Context context; 67 | context.setIncludeLoader(myIncludeLoader); 68 | 69 | std::string mapPath; 70 | int argi = 1; 71 | while (argi < argc) { 72 | if (strcmp(argv[argi], "-m") == 0) { 73 | ++argi; 74 | if (argi < argc) { 75 | mapPath = argv[argi]; 76 | ++argi; 77 | } 78 | } else if (strncmp(argv[argi], "-d", 2) == 0) { 79 | const char* def = &argv[argi][2]; 80 | if (*def == 0) { 81 | ++argi; 82 | if (argi < argc) { 83 | def = argv[argi]; 84 | } 85 | } 86 | const char* p = def; 87 | while (*p != 0 && *p != '=') { 88 | ++p; 89 | } 90 | const std::string name(def, p); 91 | std::string value; 92 | if (*p != 0) { 93 | ++p; 94 | value = p; 95 | } 96 | context.defineString(name, value); 97 | ++argi; 98 | } else if (strncmp(argv[argi], "-i", 2) == 0) { 99 | ++argi; 100 | if (argi < argc) { 101 | std::string path = argv[argi]; 102 | if (path.empty() || path.back() != SEPARATOR_CHARACTER) { 103 | path += SEPARATOR_CHARACTER; 104 | } 105 | includePaths.push_back(path); 106 | ++argi; 107 | } 108 | } else { 109 | break; 110 | } 111 | } 112 | 113 | if (argi >= argc) { 114 | std::cerr << "Makaron [-m ] [-d = ...] [-i ] |- [|-]" << std::endl; 115 | std::cerr << "map lines: : (+|:)" << std::endl; 116 | return 1; 117 | } 118 | 119 | std::string inputPath = argv[argi]; 120 | ++argi; 121 | 122 | std::string outputPath; 123 | if (argi < argc) { 124 | outputPath = argv[argi]; 125 | ++argi; 126 | } 127 | 128 | std::vector offsetMap; 129 | Makaron::String source; 130 | Makaron::String fileName; 131 | Makaron::String processed; 132 | try { 133 | if (inputPath.empty() || inputPath == "-") { 134 | source = loadEntireStream(std::cin); 135 | fileName = "stdin"; 136 | } else { 137 | std::ifstream fileStream(inputPath); 138 | if (!fileStream.good()) { 139 | std::cerr << "Could not open input file" << std::endl; 140 | return 1; 141 | } 142 | fileName = inputPath; 143 | fileStream.exceptions(std::ios_base::badbit | std::ios_base::failbit); 144 | source = loadEntireStream(fileStream); 145 | } 146 | 147 | context.process(Makaron::Span(source, fileName), processed, &offsetMap); 148 | } 149 | catch (const Makaron::Exception& x) { 150 | std::cerr << "!!!! Makaron error: " << x.getError() << std::endl 151 | << "File: " << x.getFile() << ", line: " << x.getLineNumber() << ", column: " << x.getColumnNumber() 152 | << " (@" << x.getOffset() << ")" << std::endl 153 | << std::endl 154 | << "Trace:" << std::endl; 155 | Makaron::RangeVector inputRanges = findInputRanges(offsetMap, processed.size()); 156 | for (Makaron::RangeVector::const_iterator it = inputRanges.begin(); it != inputRanges.end(); ++it) { 157 | std::pair lineAndColumn = Makaron::calculateLineAndColumn(source, it->first); 158 | std::cerr << "Line: " << lineAndColumn.first << ", column: " << lineAndColumn.second; 159 | if (it->second > it->first + 1) { 160 | std::cerr << " (@" << it->first << ".." << it->second << ')' << std::endl; 161 | } else { 162 | std::cerr << " (@" << it->first << ')' << std::endl; 163 | } 164 | } 165 | rc = 1; 166 | } 167 | 168 | if (!mapPath.empty()) { 169 | std::ofstream fileStream(mapPath); 170 | if (!fileStream.good()) { 171 | std::cerr << "Could not open map file" << std::endl; 172 | return 1; 173 | } 174 | fileStream.exceptions(std::ios_base::badbit | std::ios_base::failbit); 175 | for (std::vector::const_iterator it = offsetMap.begin(); it != offsetMap.end(); ++it) { 176 | fileStream << it->outputPoint << ':' << (it->outputPoint + it->outputStretch) << ' ' << it->inputFrom; 177 | if (it->inputLength == 0) { 178 | fileStream << '+' << std::endl; 179 | } else { 180 | fileStream << ':' << (it->inputFrom + it->inputLength) << std::endl; 181 | } 182 | } 183 | } 184 | 185 | if (outputPath.empty() || outputPath == "-") { 186 | std::cout << processed; 187 | } else { 188 | std::ofstream fileStream(outputPath); 189 | if (!fileStream.good()) { 190 | std::cerr << "Could not open output file" << std::endl; 191 | return 1; 192 | } 193 | fileStream.exceptions(std::ios_base::badbit | std::ios_base::failbit); 194 | fileStream << processed; 195 | } 196 | } 197 | catch (const std::exception& x) { 198 | std::cerr << "!!!! Exception: " << x.what() << std::endl; 199 | return 1; 200 | } 201 | catch (...) { 202 | std::cerr << "!!!! General exception" << std::endl; 203 | return 1; 204 | } 205 | return rc; 206 | } 207 | #endif 208 | 209 | -------------------------------------------------------------------------------- /CushyLint/support/buildMakaron.cmd: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | SETLOCAL ENABLEEXTENSIONS ENABLEDELAYEDEXPANSION 3 | CD /D "%~dp0" 4 | MKDIR ..\build >NUL 2>&1 5 | CALL BuildCpp.cmd release 64 ..\build\MakaronCmd.exe /I .\ .\MakaronCmd.cpp .\Makaron.cpp 6 | -------------------------------------------------------------------------------- /CushyLint/support/buildMakaron.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e -o pipefail -u 3 | cd "${0%/*}" 4 | mkdir -p "../build" 5 | ./BuildCpp.sh release 64 ../build/MakaronCmd -I ./ ./MakaronCmd.cpp ./Makaron.cpp 6 | -------------------------------------------------------------------------------- /JSConsole.mtscript/JSConsole.js: -------------------------------------------------------------------------------- 1 | if (devLayout == 'JSConsole.mtscript/JSConsole_main') { 2 | devLayout = ''; 3 | } else { 4 | devLayout = 'JSConsole.mtscript/JSConsole_main'; 5 | } 6 | verboseErrors = true; 7 | -------------------------------------------------------------------------------- /JSConsole.mtscript/JSConsole_main.cushy: -------------------------------------------------------------------------------- 1 | @define shadowBlur=8 2 | @define shadowX=4 3 | @define shadowY=2 4 | @define shadowIntensity=0.33 5 | @define titleBarHeight=24 6 | 7 | @define columns=80 8 | @define rows=25 9 | @define backgroundColor=#F0F0F0 10 | @define frameColor=#6090C0 11 | 12 | // 8x18 font 13 | @define width=(@columns * 8) 14 | @define height=(@titleBarHeight + @rows*18) 15 | @define tabSize=4 16 | 17 | bounds: { (w - @width) / 2 - @shadowX, (h - @height) / 2 - @shadowY, @width + @shadowBlur, @height + @shadowBlur } 18 | 19 | transitions: { 20 | open: { 21 | time: 0.1 22 | scale: 50 23 | opacity: 0 24 | } 25 | close: { 26 | time: 0.1 27 | scale: 50 28 | opacity: 0 29 | } 30 | } 31 | 32 | autoexecs: { 33 | { action: "set", params: { jsConsole.windowZOrder, 0 }, onReload: false } 34 | { action: "jsConsole.startup", onReload: false } 35 | { action: "jsConsole.updateConfig", params: "@columns,@rows,@tabSize" } 36 | { action: "jsConsole.fpsTick", repeat: 0.001 } 37 | { action: "jsConsole.shutdown", onClose: true, onReload: false } 38 | { action: "jsConsole.checkLitter", repeat: 0.25 } 39 | } 40 | 41 | translations: { 42 | "minOrMax:false": "Minimize", 43 | "minOrMax:true": "Maximize" 44 | } 45 | 46 | views: { 47 | // dragArea can't be in a group, or we'll just drag within that group. 48 | { 49 | type: "dragArea" 50 | bounds: { @shadowX, @shadowY, w-@shadowBlur, @titleBarHeight } 51 | hint: "Drag window" 52 | bringToFront: "auto" 53 | positionVariable: jsConsole.windowPosition 54 | zOrderVariable: jsConsole.windowZOrder 55 | cursor: "arrow" 56 | } 57 | { 58 | type: "paged", 59 | index: "jsConsole.minimized", 60 | pages: { // Notice that all pages are created on init, then shown / hidden as requested 61 | "true": { 62 | // Drop shadow (using masks to multiply four gradient fades in each direction) 63 | { 64 | type: "vector" 65 | bounds: { 0, 0, w, @titleBarHeight+@shadowBlur } 66 | code: "g=call [ mask [ wipe gradient:[linear $0 from:0.0 to:1.0] ] ]; $g 0,0,@shadowBlur,0; $g 0,0,0,@shadowBlur; $g {@width+@shadowBlur},0,{@width},0; $g 0,{@titleBarHeight+@shadowBlur},0,{@titleBarHeight}; wipe rgb(0,0,0,@shadowIntensity)" 67 | } 68 | }, 69 | "false": { 70 | { 71 | type: "paged", 72 | index: "jsConsole.opacity", 73 | pages: { // Notice that all pages are created on init, then shown / hidden as requested 74 | "100": { 75 | // Drop shadow (using masks to multiply four gradient fades in each direction) 76 | { 77 | type: "vector" 78 | code: "g=call [ mask [ wipe gradient:[linear $0 from:0.0 to:1.0] ] ]; $g 0,0,@shadowBlur,0; $g 0,0,0,@shadowBlur; $g {@width+@shadowBlur},0,{@width},0; $g 0,{@height+@shadowBlur},0,{@height}; wipe rgb(0,0,0,@shadowIntensity)" 79 | } 80 | } 81 | } 82 | } 83 | { 84 | type: "click" 85 | bounds: { @shadowX, @shadowY+@titleBarHeight, w-@shadowBlur, h-@titleBarHeight-@shadowBlur } 86 | actions: { 87 | { "click", "nop" }, 88 | { "context", "jsConsole.paste" } 89 | }, 90 | hint: "" // empty hint removes hints by underlying views from popuping up 91 | cursor: "arrow" 92 | }, 93 | 94 | { 95 | type: "transformed", 96 | opacity: jsConsole.opacity 97 | views: { 98 | { 99 | bounds: { @shadowX, @shadowY+@titleBarHeight, w-@shadowBlur, h-@titleBarHeight-@shadowBlur } 100 | dimensions: { @columns, @rows } 101 | type: "console" 102 | background: "@backgroundColor" 103 | font: { ivgfont: "monospace", size: 14, color: "black", unknown: '?' }, 104 | tabSize: @tabSize 105 | promptVariable: jsConsole.prompt 106 | outputVariable: jsConsole.output 107 | inputVariable: jsConsole.input 108 | inputAction: "jsConsole.hitEnter" 109 | margins: { 5, 5 } 110 | historyVariable: jsConsole.history 111 | } 112 | } 113 | }, 114 | 115 | { 116 | type: "rectangle" 117 | bounds: { @shadowX, @shadowY, w-@shadowBlur, h-@shadowBlur } 118 | frame: { color: "@frameColor", stroke: 2, joints: "miter" } 119 | } 120 | } 121 | } 122 | } 123 | 124 | { 125 | type: "hover", 126 | enterAction: "set" 127 | enterParams: { jsConsole.opacity, 100 } 128 | leaveAction: "set" 129 | leaveParams: { jsConsole.opacity, 90 } 130 | } 131 | 132 | // Window title and frame 133 | { 134 | type: "group" 135 | bounds: { @shadowX, @shadowY, w-@shadowBlur, @titleBarHeight } 136 | views: { 137 | { 138 | type: "rectangle" 139 | fill: "@frameColor" 140 | } 141 | 142 | { 143 | type: "caption" 144 | font: { ivgfont: "sans-serif", size: 16, color: "white" } 145 | text: "JSConsole" 146 | align: "middle center" 147 | } 148 | 149 | { 150 | type: "caption", 151 | bounds: { r - 110, t + 4, 40, 16 }, 152 | align: "middle right", 153 | font: { ivgfont: "sans-serif", size: 12, color: "white" } 154 | text: "[var]jsConsole.fps[/var] fps" 155 | } 156 | 157 | { 158 | @define reloadPath=M8,6.01h-6.58l1.94-6.01,1.72,2.22c1.96-1.39,4.35-2.21,6.93-2.21,6.62,0,12,5.38,12,12s-5.38,12-12,12-12-5.36-12-12c0-1.04.13-2.04.38-3h2.08c-.3.95-.46,1.96-.46,3,0,5.52,4.48,10,10,10,5.52,0,10-4.48,10-10,0-5.52-4.48-10-10-10-2.12,0-4.08.67-5.7,1.8l1.7,2.2zm4,1.99c2.21,0,4,1.79,4,4s-1.79,4-4,4-4-1.79-4-4,1.79-4,4-4z 159 | bounds: { r - 60, t + 4, 16, 16 }, 160 | type: "button", 161 | actions: { 162 | { "click", "reload" } 163 | { "click+shift", "reload", "reset" } 164 | }, 165 | standard: { image: { ivgCode: "bounds 0,0,16,16; scale 0.6 anchor:8,8; offset -4,-4; fill white; path svg:@reloadPath" } } 166 | down: { image: { ivgCode: "bounds 0,0,16,16; scale 0.5 anchor:8,8; offset -4,-4; fill white; path svg:@reloadPath" } } 167 | hint: "Reload all UI components" 168 | cursor: "arrow" 169 | }, 170 | 171 | { 172 | bounds: { r - 40, t + 4, 16, 16 }, 173 | type: "button", 174 | action: "jsConsole.minimize", 175 | standard: { image: { ivgCode: "bounds 0,0,16,16; fill white; star 8,9,3,6" } } 176 | down: { image: { ivgCode: "bounds 0,0,16,16; fill white; star 8,9,3,5" } } 177 | checked: { image: { ivgCode: "bounds 0,0,16,16; fill white; star 8,7,3,6 rotation:180" } } 178 | checkedDown: { image: { ivgCode: "bounds 0,0,16,16; fill white; star 8,7,3,5 rotation:180" } } 179 | hint: "[xlate]minOrMax:[var]jsConsole.minimized[/var][/xlate] window" 180 | cursor: "arrow" 181 | }, 182 | 183 | { 184 | bounds: { r - 20, t + 4, 16, 16 } 185 | type: "button" 186 | action: "jsConsole.close" 187 | standard: { image: { ivgCode: "bounds 0,0,16,16; pen white; path svg:M3,3L13,13M13,3L3,13" } } 188 | down: { image: { ivgCode: "bounds 0,0,16,16; pen white; path svg:M4,4L12,12M12,4L4,12" } } 189 | hint: "Close window" 190 | cursor: "arrow" 191 | } 192 | } 193 | } 194 | } 195 | -------------------------------------------------------------------------------- /JSConsole.mtscript/JSConsole_main.js: -------------------------------------------------------------------------------- 1 | if (!this.jsConsole) { 2 | jsConsole = { 3 | realPrint: print, 4 | lastCushyTracer: this.handleCushyTrace, 5 | windowPosition: '', 6 | windowZOrder: '', 7 | input: '', 8 | output: '', 9 | minimized: false, 10 | moreBuffered: '', 11 | noMoreBuffered: '', 12 | bufferMax: 65536, 13 | prompt: "JS> ", 14 | multiline: null, 15 | history: '', 16 | opacity: 100, 17 | globals: this, 18 | knownGlobals: { } 19 | } 20 | } 21 | 22 | Object.assign(jsConsole, { 23 | columns: 80, 24 | rows: 25, 25 | moreCounter: 0, 26 | tabSize: 4, 27 | outputLimit: 20000, 28 | commands: { 29 | '?': function() { 30 | print("\nEnter any expression to evaluate, result will be stored in _\n" 31 | + "Use single ` to enter multi-line code. End with another `\n" 32 | + "End line with ; to prevent printing the statement result.\n" 33 | + "\n" 34 | + "cls: clear screen\n" 35 | + "copy: copies console buffer to clipboard\n" 36 | + "exit: closes console\n" 37 | + "reload: reloads UI\n" 38 | + "reset: reinits JS engine and restarts UI\n"); 39 | }, 40 | '`': function() { 41 | if (jsConsole.multiline === null) { 42 | jsConsole.multiline = ''; 43 | } else { 44 | var s = jsConsole.multiline; 45 | jsConsole.multiline = null; 46 | eval.call(null, s); 47 | } 48 | }, 49 | 'exit': function() { jsConsole.close(); }, 50 | 'reload': function() { jsConsole.reload(); }, 51 | 'reset': function() { jsConsole.reset(); }, 52 | 'cls': function() { jsConsole.clearScreen(); }, 53 | 'copy': function() { writeClipboard(jsConsole.output.substr(1)); } 54 | }, 55 | clearScreen: function() { 56 | this.output = '\f'; 57 | }, 58 | updateConfig: function(config) { 59 | config = config.split(','); 60 | this.columns = +config[0]; 61 | this.rows = +config[1]; 62 | this.tabSize = +config[2]; 63 | var s = "more (y)? "; 64 | while (s.length < this.columns - 2) { 65 | s = ' ' + s; 66 | } 67 | this.morePrompt = s; 68 | }, 69 | startup: function(dims) { 70 | print = handleCushyTrace = jsConsole.printNoMore; 71 | this.output = '\f'; 72 | this.input = ''; 73 | this.printNoLF("Javascript Console. Type ? for help.\n\n"); 74 | _ = ''; 75 | for (var key in this.globals) this.knownGlobals[key] = true; 76 | }, 77 | isWaitingForMore: function() { 78 | return (this.moreCounter == 0 && this.moreBuffered !== ''); 79 | }, 80 | printNoLF: function(s) { 81 | var jc = jsConsole; 82 | jc.output += s; 83 | if (jc.output.length >= jc.outputLimit) { 84 | jc.output = "\f" + jc.output.substr(jc.outputLimit / 2); 85 | } 86 | }, 87 | printMoreNoLF: function(s) { 88 | var jc = jsConsole; 89 | var line = ''; 90 | for (var i = 0; i < s.length && jc.moreCounter > 0; ++i) { 91 | var c = s[i]; 92 | if (c == '\t') { 93 | var stop = Math.min(line.length + jc.tabSize - line.length % jc.tabSize, jc.columns); 94 | while (line.length < stop) { 95 | line += ' '; 96 | } 97 | } else if (c == '\n' || c >= ' ') { 98 | line += c; 99 | } 100 | if (c == '\n' || line.length >= jc.columns) { 101 | jc.printNoLF(line); 102 | line = ''; 103 | if (--jc.moreCounter == 0) { 104 | s = s.substr(i + 1); 105 | jc.prompt = jc.morePrompt; 106 | } 107 | } 108 | } 109 | if (jc.moreCounter == 0 && jc.moreBuffered.length < jc.bufferMax) { 110 | jc.moreBuffered += s; 111 | if (jc.moreBuffered.length >= jc.bufferMax - 28) { 112 | jc.moreBuffered = jc.moreBuffered.substr(0, jc.bufferMax - 28) + "\n!!! output buffer overflow\n"; 113 | } 114 | } 115 | }, 116 | printMore: function(s) { 117 | jsConsole.printMoreNoLF(s + '\n'); 118 | jsConsole.realPrint(s); 119 | }, 120 | printNoMore: function(s) { 121 | var jc = jsConsole; 122 | if (jc.isWaitingForMore() || jc.multiline !== null) { 123 | if (jc.noMoreBuffered.length < jc.bufferMax) { 124 | jc.noMoreBuffered += s + '\n'; 125 | if (jc.noMoreBuffered.length >= jc.bufferMax - 28) { 126 | jc.noMoreBuffered = jc.noMoreBuffered.substr(0, jc.bufferMax - 28) + "\n!!! output buffer overflow\n"; 127 | } 128 | } 129 | } else { 130 | jc.printNoLF(s + '\n'); 131 | } 132 | jc.realPrint(s); 133 | }, 134 | paste: function() { 135 | jsConsole.input += readClipboard(); 136 | }, 137 | hitEnter: function() { 138 | var jc = jsConsole; 139 | var input = jc.input; 140 | jc.input = ''; 141 | if (jc.isWaitingForMore()) { 142 | jc.moreCounter = jc.rows - 1; 143 | var s = jc.moreBuffered; 144 | jc.moreBuffered = ''; 145 | if (input == '' || input == 'y') { 146 | jc.printMoreNoLF(s); 147 | } 148 | } else { 149 | jc.printNoLF(jc.prompt + input + '\n'); 150 | jc.prompt = ''; 151 | print = jsConsole.printMore; 152 | try { 153 | jc.moreCounter = jc.rows - 1; 154 | if (jc.commands[input]) { 155 | jc.commands[input](); 156 | } else if (jc.multiline !== null) { 157 | jc.multiline += input + '\n'; 158 | } else { 159 | _ = eval.call(null, input); 160 | if (input.length > 0 && input[input.length - 1] !== ';') { 161 | var type = typeof _; 162 | var s = _; 163 | if (type == 'string') { 164 | s = JSON.stringify(_); 165 | } else if (type == 'object') { 166 | var gotObject = false; 167 | s = JSON.stringify(_, function(key, value) { 168 | if (typeof value == 'object' && !Array.isArray(value)) { 169 | gotObject = true; 170 | } 171 | return value; 172 | }); 173 | if (gotObject) { 174 | s = JSON.stringify(_, null, 2).replace(/\n/g, '\n '); 175 | } 176 | } 177 | print(' = ' + s); 178 | } 179 | } 180 | } 181 | catch (e) { 182 | print("!!! " + e); 183 | } 184 | print = jsConsole.printNoMore; 185 | } 186 | if (jc.multiline !== null) { 187 | jc.prompt = '..> '; 188 | } else if (jc.isWaitingForMore()) { 189 | jc.prompt = jc.morePrompt; 190 | } else { 191 | jc.printNoLF(jc.noMoreBuffered); 192 | jc.noMoreBuffered = ''; 193 | jc.prompt = "JS> "; 194 | } 195 | }, 196 | checkLitter: function() { 197 | var known = this.knownGlobals; 198 | for (var key in this.globals) { 199 | if (!(key in known)) { 200 | print("New global: " + key); 201 | known[key] = true; 202 | } 203 | } 204 | }, 205 | minimize: { 206 | execute: function() { jsConsole.minimized = !jsConsole.minimized; }, 207 | checked: function() { return !jsConsole.minimized; } 208 | }, 209 | fpsLastTick: Date.now(), 210 | fpsCounter: 0, 211 | fpsTick: function() { 212 | ++this.fpsCounter; 213 | var now = Date.now(); 214 | if (now >= this.fpsLastTick + 1000) { 215 | this.fps = Math.round(this.fpsCounter * 1000 / (now - this.fpsLastTick)); 216 | this.fpsLastTick = now; 217 | this.fpsCounter = 0; 218 | } 219 | }, 220 | fps: 0.0, 221 | close: function() { devLayout = ''; }, 222 | reload: function() { performCushyAction('reload'); print("ok"); }, 223 | reset: function() { performCushyAction('reload', 'reset'); }, 224 | shutdown: function() { 225 | print = this.realPrint; 226 | handleCushyTrace = this.lastCushyTracer; 227 | print("SHUTTING DOWN"); 228 | delete jsConsole; 229 | } 230 | }); 231 | -------------------------------------------------------------------------------- /JSConsole.mtscript/JSConsole_main.schema: -------------------------------------------------------------------------------- 1 | include: ../../Resources/microtonic.schema 2 | resources: ../ 3 | resources: ../../Resources 4 | 5 | = 6 | | { action: "jsConsole.startup" } 7 | | { action: "jsConsole.updateConfig", params: } 8 | | { action: "jsConsole.fpsTick" } 9 | | { action: "jsConsole.shutdown" } 10 | | { action: "jsConsole.paste" } 11 | | { action: "jsConsole.hitEnter" } 12 | | { action: "jsConsole.minimize" } 13 | | { action: "jsConsole.checkLitter" } 14 | | { action: "jsConsole.close" } 15 | 16 | = 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Microtonic Scripts SDK 2 | 3 | This repository contains all the necessary documentation and resources to create GUI scripts for Microtonic. The 4 | scripting engine in Microtonic uses a proprietary JavaScript engine based on ECMAScript 3. The engine only works when 5 | the Microtonic window is open. There is currently no way to create real-time scripts that process MIDI or audio. Apart 6 | from these restrictions, a script can do pretty much anything with the data in Microtonic, and the user interface can 7 | look and behave in any way you can imagine. 8 | 9 | Disclaimer: many proprietary technologies, formats, and languages are involved in creating user interfaces for 10 | Sonic Charge plugins. These technologies have evolved organically over time and will continue to do so in the future. 11 | There is functional overlap and inconsistencies, and there is no guarantee that a script that works in the current 12 | version of Microtonic will work in the next (even though good compatibility is something that we strive for at 13 | Sonic Charge). 14 | 15 | The documentation in this repository was written for Microtonic version 3.3.4 (build 1048). 16 | 17 | ## Technology Overview 18 | 19 | Here is a brief list of the technologies used in Microtonic GUIs: 20 | 21 | - _Cushy_: the layout engine and file format for describing layouts, based on _Numbstrict_ with _Makaron_ support. 22 | - _ImpD_: a simple imperative computer language disguised as a data format, or the other way around. 23 | - _IVG_ (Imperative Vector Graphics): a language and file-format for 2D vector graphics, based on _ImpD_. 24 | - _Makaron_: a macro expansion syntax, used to make `.cushy` files easier to write. 25 | - _Numbstrict_: an object notation format similar to (but not compatible with) JSON. 26 | - _NuXJScript_: our JavaScript engine, fully ECMAScript 3 compliant with features from ECMAScript 5. 27 | - _PikaScript_: our legacy script language used by older Microtonic scripts and offline tools. 28 | 29 | ## Repository Structure 30 | 31 | - `CushyLint`: 32 | 1. Command-line syntax checker for `.cushy` files. 33 | 2. Contains [`cushy.schema`](CushyLint/cushy.schema), the official reference for the `.cushy` format. 34 | 35 | - `docs`: 36 | - [ImpD Documentation](docs/ImpD%20Documentation.md) 37 | - [IVG Documentation](docs/IVG%20Documentation.md) 38 | - [Makaron Documentation](docs/Makaron%20Documentation.md) 39 | - [Microtonic JS Reference](docs/Microtonic%20JS%20Reference.md) 40 | 41 | - `ivgfiddle`: a browser "playground" for experimenting with _IVG_ (compiled with _emscripten_). 42 | 43 | - `IVGFontConverter`: a converter from `.ttf` and `.otf` to `.ivgfont` (requires _node.js_). 44 | 45 | - `JSConsole.mtscript`: an interactive Javascript console for Microtonic. 46 | 47 | - `legacy`: contains documentation for the legacy scripting engine (based on _PikaScript_). 48 | 49 | - `tmLanguages`: syntax highlighting support for Sonic Charge formats and languages. 50 | 51 | ### Cushy 52 | 53 | _Cushy_ is the GUI / layout engine used in all Sonic Charge products. `.cushy` files define the layout of views and 54 | configure how the user can interact with the plugin through _GUI variables_ and _GUI actions_. The format is based 55 | on _Numbstrict_, the object notation format used in all Sonic Charge products. _Numbstrict_ is similar to JSON with 56 | the following differences: 57 | 58 | 1. C-style comments are supported. 59 | 2. You use curly brackets (`{` and `}`) for both structures and arrays. 60 | 3. To differentiate empty structures from empty arrays, you may use this syntax: `{ : }`. 61 | 4. You may express integer values as hexadecimal numbers in this format: `0xABCD`. 62 | 5. Real values include infinity (`inf`) and the NaN value (`nan`). 63 | 6. Free-form text values without quotes are allowed in many cases. 64 | 7. You can use `\U` inside quoted strings to escape a 32-bit Unicode character, e.g., `\U0001F9FF`. 65 | 66 | Here is an "outline" of the Cushy file structure: 67 | 68 | bounds: { , , , } 69 | autoexecs: { 70 | ... actions to run on open, close, or regularly on a timer 71 | } 72 | transitions: { 73 | ... visual transition effects applied when this Cushy is opened or closed 74 | } 75 | translations: { 76 | ... special string translations used for this Cushy. 77 | } 78 | views: { 79 | ... view definitions 80 | } 81 | 82 | In Cushy, it's often possible to write mathematical expressions where numerical constants are expected. In these places, 83 | `$` may be used to insert the default value for the field. E.g., `updateRate: $*2` would set `updateRate` to twice the 84 | default. For rectangles such as view bounds you can also use the following variables: `t`, `l`, `w`, `h`, `r`, `b` 85 | for _top_, _left_, _width_, _height_, _right_ and _bottom_ of the default rectangle. E.g. 86 | `bounds: { l+10,t+10,h-20,w-20 }`. The default rectangle for a view bound is the full bounding box of the parent view. 87 | 88 | The _Numbstrict_ format can be challenging to write correctly, especially when containing deeply nested hierarchical 89 | views and actions. Therefore we created _CushyLint_, a command-line tool to check the syntax of a `.cushy` file against 90 | the official "schema" specification. Simple run `CushyLint` (Mac) or `CushyLint.bat` (Windows) from a command-line 91 | prompt with the single argument specifying a single `.cushy` file path to check or a directory if you want to check 92 | multiple files. Directories must end with a slash (`/` or `\`). 93 | 94 | The files are checked against the official `cushy.schema` file in the `CushyLint` directory, plus any other `.schema` 95 | files existing in the directory next to the `.cushy` file that you are checking. The `cushy.schema` file is designed to 96 | be readable and contains lots of comments, thus also serving as a kind of official reference documentation on `.cushy` 97 | files, available view types, and built-in actions. 98 | 99 | Furthermore, you can use macros when writing `.cushy` files for easier development and maintenance. See 100 | [Makaron Documentation](docs/Makaron%20Documentation.md) for documentation on the macro expansion language we use. Macros 101 | you write are expanded when `.cushy` files are loaded inside the plugin, before they are parsed. 102 | 103 | See [`cushy.schema`](CushyLint/cushy.schema) and [Microtonic JS Reference](docs/Microtonic%20JS%20Reference.md) for more 104 | information on how to write Cushy. 105 | 106 | ### IVGFiddle 107 | 108 | Included in this distribution is a standalone .html application called _IVGFiddle_. You can run it simply by opening the 109 | [`ivgfiddle.html`](https://htmlpreview.github.io/?https://github.com/malstrom72/microtonic-scripts-sdk/blob/main/ivgfiddle/ivgfiddle.html) 110 | file in your favorite browser (Google Chrome). It will let you experiment with IVG code and see the graphical output in 111 | real-time. 112 | 113 | See [IVG Documentation](docs/IVG%20Documentation.md) for more information on IVG. 114 | 115 | ### IVGFontConverter 116 | 117 | Cushy (and IVG) uses a proprietary file format for fonts: `.ivgfont`. You can use _IVGFontConverter_ to convert 118 | a _TrueType_ or _OpenType_ font to this format. To run, you must install [node.js](https://nodejs.org/en/). Then use 119 | it like this: 120 | 121 | node IVGFontConverter.node.js [ ?|-|[,,...] ] [ [,,...] ] > 122 | 123 | ? List all GSUB features 124 | - No extra GSUB feature 125 | Enable GSUB feature by [ 4 | 5 | 6 | ivgfiddle 7 | 8 | 53 | 54 |
55 |
56 |
57 |
58 |

59 | 				
60 |
61 |
62 |
63 |
64 | 65 | This text is displayed if your browser does not support HTML5 Canvas. 66 | 67 |
68 |
69 |
70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /ivgfiddle/ivgfiddle.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const MAX_LOG_SIZE = 64 * 1024; 4 | const MAX_LOG_LINES = 1000; 5 | 6 | const leftPanelElement = document.getElementById("leftPanel"); 7 | const leftRightSplitElement = document.getElementById('leftRightSplit'); 8 | const traceElement = document.getElementById('trace'); 9 | const traceDiv = document.getElementById('traceDiv'); 10 | const ivgCanvas = document.getElementById('ivgCanvas'); 11 | const ivgContext = ivgCanvas.getContext("2d"); 12 | 13 | let allLogLines = ''; 14 | let traceLinesCount = 0; 15 | let lastLogLine = null; 16 | let repeatingLogLineCount = 0; 17 | 18 | function clearTrace() { 19 | allLogLines = ''; 20 | traceLinesCount = 0; 21 | lastLogLine = null; 22 | repeatingLogLineCount = 0; 23 | traceElement.textContent = ''; 24 | traceDiv.scrollTop = 0; 25 | } 26 | 27 | function trace(message) { 28 | const allLines = traceElement.textContent; 29 | while (allLogLines.length > MAX_LOG_SIZE || traceLinesCount >= MAX_LOG_LINES) { 30 | const offset = allLogLines.indexOf("\n"); 31 | if (offset < 0) { 32 | break; 33 | } 34 | allLogLines = allLogLines.substr(offset + 1); 35 | --traceLinesCount; 36 | } 37 | if (lastLogLine === message) { 38 | if (repeatingLogLineCount > 1) { 39 | const offset = allLogLines.lastIndexOf(' *'); 40 | if (offset >= 0) { 41 | allLogLines = allLogLines.substr(0, offset); 42 | } 43 | } else { 44 | allLogLines = allLogLines.substr(0, allLogLines.length - 1); // remove last LF 45 | } 46 | ++repeatingLogLineCount; 47 | allLogLines += " *" + repeatingLogLineCount + "\n"; 48 | } else { 49 | allLogLines += message + "\n"; 50 | ++traceLinesCount; 51 | lastLogLine = message; 52 | repeatingLogLineCount = 1; 53 | } 54 | traceElement.textContent = allLogLines; 55 | traceDiv.scrollTop = traceDiv.scrollHeight; 56 | } 57 | 58 | // Can't use cwrap to pass very long strings, as they are placed on the stackm and not the heap. 59 | const rasterizeIVG = function(source, scaling) { 60 | const size = Module.lengthBytesUTF8(source) + 1; 61 | const stringPointer = Module._malloc(size); 62 | Module.stringToUTF8(source, stringPointer, size); 63 | const result = Module._rasterizeIVG(stringPointer, scaling); 64 | Module._free(stringPointer); 65 | return result; 66 | }; 67 | const deallocatePixels = Module._deallocatePixels; 68 | 69 | function runIVG() { 70 | clearTrace(); 71 | trace("Running IVG"); 72 | const linesCountWas = traceLinesCount; 73 | const start = Date.now(); 74 | const sourceCode = aceEditor.getValue(); 75 | localStorage.setItem("ivgSource", sourceCode); 76 | localStorage.setItem("runOnStartup", false); 77 | let ok = false; 78 | try { 79 | const pixelRatio = window.devicePixelRatio; 80 | const rasterPointer = rasterizeIVG(sourceCode, pixelRatio); 81 | const end = Date.now(); 82 | if (rasterPointer !== 0) { 83 | let dimensions = new Int32Array(Module.HEAPU32.buffer, rasterPointer, 4); 84 | const left = dimensions[0]; 85 | const top = dimensions[1]; 86 | const width = dimensions[2]; 87 | const height = dimensions[3]; 88 | dimensions = null; 89 | let pixelData = new Uint8Array(Module.HEAPU32.buffer, rasterPointer + 4 * 4, width * height * 4); 90 | deallocatePixels(rasterPointer); 91 | ivgCanvas.width = width; 92 | ivgCanvas.height = height; 93 | const imageData = ivgContext.createImageData(width, height); 94 | imageData.data.set(pixelData); 95 | pixelData = null; 96 | ivgCanvas.style.width = width / pixelRatio + "px"; 97 | ivgCanvas.style.height = height / pixelRatio + "px"; 98 | ivgCanvas.style.transform = "translate(" + left / pixelRatio + "px," + top / pixelRatio + "px)"; 99 | ivgContext.putImageData(imageData, 0, 0); 100 | trace("Completed IVG"); 101 | trace("Time spent: " + (end - start) + "ms"); 102 | ok = true; 103 | } else { 104 | trace("Aborted IVG"); 105 | } 106 | localStorage.setItem("runOnStartup", true); 107 | } 108 | catch (e) { 109 | trace("Rasterization crashed"); 110 | trace(e); 111 | } 112 | if (!ok) { 113 | ivgContext.beginPath(); 114 | ivgContext.moveTo(0, 0); 115 | ivgContext.lineTo(ivgCanvas.width, ivgCanvas.height); 116 | ivgContext.moveTo(0, ivgCanvas.height); 117 | ivgContext.lineTo(ivgCanvas.width, 0); 118 | ivgContext.strokeStyle = "red"; 119 | ivgContext.lineWidth = 10; 120 | ivgContext.stroke(); 121 | } 122 | } 123 | 124 | const aceEditor = ace.edit("editor"); 125 | aceEditor.setTheme("ace/theme/twilight"); 126 | const aceSession = aceEditor.getSession(); 127 | aceSession.setUseSoftTabs(false); 128 | aceSession.setMode("ace/mode/ivg"); 129 | let recompileTimer = null; 130 | aceSession.on('change', function(e) { 131 | if (recompileTimer !== null) { 132 | clearTimeout(recompileTimer); 133 | recompileTimer = null; 134 | }; 135 | recompileTimer = setTimeout(runIVG, 500); 136 | }); 137 | 138 | let isDragging = false; 139 | let currentX; 140 | let currentPanelWidth; 141 | leftRightSplitElement.addEventListener('mousedown', function(e) { 142 | isDragging = true; 143 | currentX = e.clientX; 144 | currentPanelWidth = leftPanelElement.offsetWidth; 145 | e.preventDefault(); 146 | }); 147 | document.addEventListener('mousemove', function(e) { 148 | if (isDragging) { 149 | leftPanelElement.style.width = (currentPanelWidth + e.clientX - currentX) + 'px'; 150 | } 151 | }); 152 | document.addEventListener('mouseup', function(e) { 153 | isDragging = false; 154 | }); 155 | -------------------------------------------------------------------------------- /ivgfiddle/setupModule.js: -------------------------------------------------------------------------------- 1 | Module = { 2 | print: function(text) { trace(text); }, 3 | printErr: function(text) { trace(text); }, 4 | onRuntimeInitialized: function() { 5 | let initSource = localStorage.getItem("ivgSource"); 6 | if (initSource == null || initSource === '') { 7 | initSource = Module.FS.readFile('demoSource.ivg', { encoding: 'utf8' }); 8 | } 9 | ace.edit("editor").setValue(initSource); 10 | if (localStorage.getItem("runOnStartup") === 'false') { 11 | trace("Last execution was terminated. Modify IVG code to run again."); 12 | } else { 13 | runIVG(); 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /legacy/PikaScript Documentation.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malstrom72/microtonic-scripts-sdk/90d8465f350b939feb102718a0cee1a6a903a767/legacy/PikaScript Documentation.txt -------------------------------------------------------------------------------- /legacy/Prompt.pika: -------------------------------------------------------------------------------- 1 | // TITLE 2 | // Prompt (script for MicroTonic 3.0) 3 | // 4 | // DESCRIPTION 5 | // Lets the user run PikaScript statements interactively. The initial default text is read from the clipboard 6 | // (but only used if it represent a single PikaScript statement). The entered statement is copied to the clipboard 7 | // before executing. 8 | // 9 | // print() is overloaded and will accumulate all output (to a limit) and display with display() after execution. 10 | // 11 | // AUTHOR 12 | // Magnus Lidström 13 | // 14 | // VERSION 15 | // 1.0 16 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 17 | 18 | include('stdlib.pika'); 19 | include('help.pika'); 20 | 21 | function { // Implemented as an anonymous function to allow local variables. 22 | trace(); // Turn off any tracing (debugging etc). 23 | s = readClipboard(); 24 | default = void; 25 | try(>if (find(s, "\r\n") >= length(s) && parse(s, false) == length(s)) default = s); 26 | for (;true;) { // Infinite loop is ok since ask() will throw an exception if the user presses cancel. 27 | s = ask('Enter PikaScript (e.g. "help()")', default); 28 | writeClipboard(s); 29 | default = void; 30 | originalPrint = ::print; 31 | ::_output = ''; 32 | ::print = function { ::_output #= $0 # LF }; 33 | r = void; 34 | x = try(>r = evaluate(s, @::)); 35 | o = ::_output; 36 | delete(@::_output); 37 | ::print = originalPrint; 38 | if (x != void || r != void) { 39 | if (o !== '') o #= '--------' # LF; 40 | if (x != void) o #= 'Error: ' # x 41 | else o #= 'Result: ' # r 42 | }; 43 | if (o !== '') display(o{:1000} # (if (length(o) > 1000) ' +++ TRUNCATED LONG STRING +++')); 44 | } 45 | }(); 46 | -------------------------------------------------------------------------------- /legacy/Test MRPikaEngine.pika: -------------------------------------------------------------------------------- 1 | // TITLE 2 | // Test MRPikaEngine (script for Microtonic 3.0) 3 | // 4 | // DESCRIPTION 5 | // Unit tests for the Microtonic PikaScript interface. 6 | // 7 | // AUTHOR 8 | // Magnus Lidström 9 | // 10 | // VERSION 11 | // 1.0 12 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 13 | 14 | run('unittests.pika'); 15 | display('PikaScript unit tests successful'); 16 | run('debug.pika'); 17 | 18 | // XorshiftPRNG is an implementation of the elegant Xorshift Pseudo Random Number Generator algorithm by 19 | // George Marsaglia (http://en.wikipedia.org/wiki/Xorshift) 20 | // 21 | // It also serves as an example of how to write object-oriented with Pika. XorshiftPRNG can be used like this: 22 | // 23 | // construct(@prng, XorshiftPRNG, time(), ~time()); // setup with seed time() and ~time() 24 | // print(prng.nextInt()); 25 | // print(prng.nextFloat()); 26 | // 27 | // ... or 28 | // 29 | // prng = new(XorshiftPRNG, time(), ~time()); // this time, prng becomes a reference, so that it can be shared etc 30 | // print([prng].nextInt()); 31 | // print([prng].nextFloat()); 32 | // prng = void; 33 | // gc(); // garbage collect to kill it 34 | // 35 | XorshiftPRNG.NORM = 1 / ~0; 36 | XorshiftPRNG = function { 37 | vargs(, @seedX, @seedY); 38 | defaults(@seedX,123456789 , @seedY,362436069); 39 | t = this(); 40 | [t].x = seedX; 41 | [t].y = seedY; 42 | [t].nextInt = function { 43 | t = this(); 44 | z = (([t].x ^ ([t].x << 10)) & 0xFFFFFFFF); 45 | [t].x = [t].y; 46 | [t].y = (([t].y ^ ([t].y >> 13)) ^ (z ^ (z >> 10)) & 0xFFFFFFFF); 47 | }; 48 | [t].nextFloat = function { [this()].nextInt() * XorshiftPRNG.NORM } 49 | }; 50 | 51 | predChar = function { char(ordinal($0) - 1) }; 52 | succChar = function { char(ordinal($0) + 1) }; 53 | 54 | // 55 | // MAIN FUNCTION 56 | // 57 | function { // Implemented as an anonymous function to allow local variables. 58 | 59 | assert(> try(> assert(> false)) != void); // Just double-checking that assertion is enabled. 60 | 61 | compose(@CORRECT_SEQUENCE, 2112846788, 20866602, 3238921223, 965798894, 3232856296, 3130433881, 3217095090, 1609483805, 3823436117, 120426956); 62 | construct(@rnd, XorshiftPRNG, 123456789, 362436069); 63 | 64 | // Test that random sequence is correct and deterministic 65 | for (i = 0; i < 10; ++i) append(@testSequence, rnd.nextInt()); 66 | dump(@testSequence); 67 | assert(> equal(@testSequence, @CORRECT_SEQUENCE)); 68 | 69 | quantize = function { min(floor($0 * $1) / ($1 - 1), 1.0) }; 70 | randomBool = >((rnd.nextInt() & 1) != 0); 71 | randomMidiValue = >(if ((rnd.nextInt() & 1) != 0) (rnd.nextInt() & 127) else void); 72 | 73 | // 74 | // Constants tests 75 | // 76 | 77 | assert(> CHANNEL_COUNT == 8); 78 | assert(> PATTERN_COUNT == 12); 79 | assert(> LAST_PATTERN == 'l'); 80 | assert(> PROGRAM_COUNT == 16); 81 | assert(> PATTERN_STEP_COUNT == 16); 82 | assert(> GLOBAL_PARAM_COUNT == 15); 83 | assert(> FREQ_VALUE_C4 == 0.4725600599127338); 84 | assert(> OCTAVE_STEP == 0.1003433318879937); 85 | 86 | assert(> PARAMS.n == 215); 87 | assert(> PARAMS.0 == 'Morph'); 88 | assert(> PARAMS.1 == 'Pattern'); 89 | assert(> PARAMS.15 == 'OscWave.1'); 90 | assert(> PARAMS.20 == 'ModRate.1'); 91 | assert(> PARAMS.40 == 'OscWave.2'); 92 | assert(> PARAMS.214 == 'ModVel.8'); 93 | assert(> DRUM_PATCH_PARAMS.n == 25); 94 | assert(> DRUM_PATCH_PARAMS.0 == 'OscWave'); 95 | assert(> DRUM_PATCH_PARAMS.1 == 'OscFreq'); 96 | assert(> DRUM_PATCH_PARAMS.5 == 'ModRate'); 97 | assert(> DRUM_PATCH_PARAMS.24 == 'ModVel'); 98 | assert(> PARAM_STEPS.OscWave.1 == 3); 99 | assert(> DRUM_PATCH_PARAM_STEPS.OscWave == 3); 100 | 101 | display(bake("OS: {PLATFORM.OS}\nCPU: {PLATFORM.CPU}\nTarget: {BUILD.TARGET}\nVersion: {BUILD.VERSION}\nBuild: {BUILD.NUMBER}\nBuild Date: {BUILD.DATE} {BUILD.TIME}\nCompiler: {BUILD.COMPILER}\nLibs: {BUILD.LIBS}")); 102 | display(bake("Documentation: {DIRS.DOCUMENTATION}\n\nPresets: {DIRS.PRESETS}\n\nDrum Patches: {DIRS.DRUM_PATCHES}\n\nScripts: {DIRS.SCRIPTS}")); 103 | 104 | // 105 | // Input tests 106 | // 107 | 108 | assert(> try(abort) == void); 109 | display("Your wrote: " # ask("Write something profound for me please...")); 110 | 111 | // 112 | // File and dir tests 113 | // 114 | 115 | assert(> fullPath(void, 'abcd.efg') == DIRS.SCRIPTS # 'abcd.efg'); 116 | if (PLATFORM.OS == 'windows') { 117 | drive = fullPath('/', ''); 118 | assert(> wildmatch(drive, '{?}:\', @drive)); 119 | drive = lower(drive); 120 | assert(> lower(fullPath('/dir/subdir/file.txt', '../')) == drive # ':\dir\subdir\'); 121 | assert(> lower(fullPath('/dir/subdir/file.txt', '..\..\')) == drive # ':\dir\'); 122 | assert(> lower(fullPath('c:\dir\subdir\file.txt', '..\')) == 'c:\dir\subdir\'); 123 | assert(> lower(fullPath('c:\dir\subdir\file.txt', '..\..\')) == 'c:\dir\'); 124 | } else if (PLATFORM.OS == 'mac') { 125 | assert(> fullPath('/dir/subdir/file.txt', '../') == '/dir/subdir/'); 126 | assert(> fullPath('/dir/subdir/file.txt', '../../') == '/dir/'); 127 | } else { 128 | assert(false); 129 | }; 130 | 131 | display("Next up, select any file anywhere, do not press cancel."); 132 | display("You selected: " # browse()); 133 | display("Ok, this time, press cancel."); 134 | for (; { 135 | s = void; 136 | assert(> try(>s = browse()) == void); 137 | if (s != void) { 138 | display("You did not press cancel. Try again."); 139 | true 140 | } else 141 | false 142 | }; ); 143 | display("Thanks. Next we are going to test saving a text-file somewhere. Please select the file name and location."); 144 | 145 | path = browse('save'); 146 | save(path, 'One Ring to bring them all and in the darkness bind them'); 147 | assert(> load(path) == 'One Ring to bring them all and in the darkness bind them'); 148 | filename = path{rfind(path, '\/') + 1:}; 149 | found = false; 150 | dir(fullPath(path, "../"), >{ 151 | args(@fn, @attributes, @created, @modified, @filesize, @macFileType); 152 | if (fn == filename) { 153 | display(bake("Found the file:\n\nFilename: {fn}\nAttributes: {attributes}\nCreated: {created}\nModified: {modified}\nSize: {filesize}\nMac File Type: {macFileType}")); 154 | found = true; 155 | }; 156 | }); 157 | assert(> found); 158 | display('File tests done. You may now delete the file.'); 159 | 160 | // 161 | // Parsing tests 162 | // 163 | 164 | parseArray('{ 1, 2, 3, 4, 5 }', @array); 165 | assert(> equal(@array, compose(@temp, 1, 2, 3, 4, 5))); 166 | parseArray("{ 1, { 'sub', 'array' }, 2, 3, 4, 5 }", @array); 167 | assert(> equal(@array, compose(@temp, 1, "{ 'sub', 'array' }", 2, 3, 4, 5))); 168 | parseStruct('{ first=1, second:2, third="three" }', @struct); 169 | assert(> struct.first == 1); 170 | assert(> struct.second == 2); 171 | assert(> struct.third == '"three"'); 172 | parseStruct("{ first=4, second : 5 /* comment */\nthird /* another comment */ = {\n\t\tsub='yes', dub='no'\n}; fourth=\"4\" }", @struct); 173 | assert(> struct.first == 4); 174 | assert(> struct.second == 5); 175 | assert(> struct.third == "{\n\t\tsub='yes', dub='no'\n}"); 176 | assert(> struct.fourth == '"4"'); 177 | parseStruct(struct.third, @subStruct); 178 | assert(> subStruct.sub == "'yes'"); 179 | assert(> subStruct.dub == "'no'"); 180 | 181 | // 182 | // Random tests 183 | // 184 | 185 | prune(@gotcha); 186 | 187 | for (count = 0; { 188 | i = round(random(100)); 189 | if (!exists(@gotcha[i])) { gotcha[i] = true; ++count }; 190 | ( count < 101 ) 191 | };); 192 | 193 | prune(@gotcha); 194 | 195 | for (count = 0; { 196 | i = randomInt() >> (32 - 7); 197 | if (!exists(@gotcha[i])) { gotcha[i] = true; ++count }; 198 | ( count < 128 ) 199 | };); 200 | 201 | prune(@gotcha); 202 | 203 | for (count = 0; { 204 | i = (randomInt() & 127); 205 | if (!exists(@gotcha[i])) { gotcha[i] = true; ++count }; 206 | ( count < 128 ) 207 | };); 208 | 209 | // 210 | // Clipboard test 211 | // 212 | 213 | writeClipboard('test'); 214 | assert(> readClipboard() == 'test'); 215 | 216 | display('Preset tests will now commence. This may take a little while. Please answer YES to continue on any time-out messages.'); 217 | 218 | // 219 | // Preset tests 220 | // 221 | 222 | for (programNumber = 1; programNumber <= PROGRAM_COUNT; ++programNumber) { 223 | select('program', programNumber); 224 | assert(> selected('program') == programNumber); 225 | 226 | createElement('preset', @testPreset); 227 | 228 | testPreset.name = { for (s = ''; length(s) < 100;) s #= char(ordinal('a') + rnd.nextInt() % 26); ( s ) }; 229 | testPreset.Tempo = rnd.nextFloat() * 999; 230 | for (i = 0; i < GLOBAL_PARAM_COUNT; ++i) { 231 | param = PARAMS[i]; 232 | y = rnd.nextFloat(); 233 | if (exists(@::PARAM_STEPS[param])) y = quantize(y, ::PARAM_STEPS[param]); 234 | testPreset[param] = y; 235 | }; 236 | for (ch = 1; ch <= CHANNEL_COUNT; ++ch) { 237 | for (i = 0; i < DRUM_PATCH_PARAMS.n; ++i) { 238 | param = DRUM_PATCH_PARAMS[i]; 239 | y = rnd.nextFloat(); 240 | if (exists(@::DRUM_PATCH_PARAM_STEPS[param])) y = quantize(y, ::DRUM_PATCH_PARAM_STEPS[param]); 241 | testPreset.drumPatches[ch][param] = y; 242 | }; 243 | for (ptn = 'a'; ptn <= LAST_PATTERN; ptn = succChar(ptn)) { 244 | testPreset.patterns[ptn].length = 1 + (rnd.nextInt() & 0xF); 245 | accents = fills = triggers = ''; 246 | for (s = 0; s < PATTERN_STEP_COUNT; ++s) { 247 | accents #= '-#'{rnd.nextInt() & 1}; 248 | fills #= '-#'{rnd.nextInt() & 1}; 249 | triggers #= '-#'{rnd.nextInt() & 1}; 250 | }; 251 | testPreset.patterns[ptn][ch].accents = accents; 252 | testPreset.patterns[ptn][ch].fills = fills; 253 | testPreset.patterns[ptn][ch].triggers = triggers; 254 | }; 255 | }; 256 | 257 | setElement('preset', @testPreset); 258 | 259 | getElement('preset', @p); 260 | s = marshal('preset', @p); 261 | assert(> isMarshaledFormat('preset', s)); 262 | unmarshal('preset', s, @p2); 263 | foreach(@p, >{ if (classify($2) == 'number') assert(trunc(p2[$1], 4) == trunc($2, 4)) else assert(p2[$1] == $2) }); 264 | 265 | for (i = 0; i < GLOBAL_PARAM_COUNT; ++i) { 266 | if (PARAMS[i] != 'Morph') { // Morph is not a preset parameter. 267 | trunced = trunc(p[PARAMS[i]], 4); 268 | assert(> trunc(testPreset[PARAMS[i]], 4) == trunced); 269 | assert(> trunc(getParam(PARAMS[i]), 4) == trunced); 270 | assert(> trunc(p2[PARAMS[i]], 4) == trunced); 271 | }; 272 | }; 273 | 274 | for (ch = 1; ch <= CHANNEL_COUNT; ++ch) { 275 | select('channel', ch); 276 | assert(> selected('channel') == ch); 277 | 278 | getElement('drumPatch', @dp); 279 | s = marshal('drumPatch', @dp); 280 | assert(> isMarshaledFormat('drumPatch', s)); 281 | unmarshal('drumPatch', s, @dp2); 282 | 283 | for (i = 0; i < DRUM_PATCH_PARAMS.n; ++i) { 284 | trunced = trunc(dp[DRUM_PATCH_PARAMS[i]], 4); 285 | assert(> trunc(testPreset.drumPatches[ch][DRUM_PATCH_PARAMS[i]], 4) == trunced); 286 | assert(> trunc(getParam(DRUM_PATCH_PARAMS[i] # '.' # ch), 4) == trunced); 287 | assert(> trunc(dp2[DRUM_PATCH_PARAMS[i]], 4) == trunced); 288 | }; 289 | }; 290 | 291 | for (ptn = 'a'; ptn <= LAST_PATTERN; ptn = succChar(ptn)) { 292 | select('pattern', ptn); 293 | assert(> selected('pattern') == ptn); 294 | 295 | getElement('pattern', @pt); 296 | s = marshal('pattern', @pt); 297 | assert(> isMarshaledFormat('pattern', s)); 298 | unmarshal('pattern', s, @pt2); 299 | 300 | assert(> pt.length == pt2.length); 301 | assert(> pt.length == testPreset.patterns[ptn].length); 302 | 303 | for (s = 0; s < PATTERN_STEP_COUNT; ++s) { 304 | for (ch = 1; ch <= CHANNEL_COUNT; ++ch) { 305 | assert(> pt[ch].accents == pt2[ch].accents); 306 | assert(> pt[ch].fills == pt2[ch].fills); 307 | assert(> pt[ch].triggers == pt2[ch].triggers); 308 | assert(> pt[ch].accents == testPreset.patterns[ptn][ch].accents); 309 | assert(> pt[ch].fills == testPreset.patterns[ptn][ch].fills); 310 | assert(> pt[ch].triggers == testPreset.patterns[ptn][ch].triggers); 311 | }; 312 | }; 313 | }; 314 | }; 315 | 316 | // 317 | // Midi Config tests 318 | // 319 | 320 | compose(@MODE_NAMES, 'SwitchNext', 'SwitchNow', 'Retrigger', 'RetriggerGated'); 321 | 322 | for (testCounter = 0; testCounter < 16; ++testCounter) { 323 | createElement('midiConfig', @mc); 324 | for (ch = 1; ch <= CHANNEL_COUNT; ++ch) { 325 | for (i = 0; i < DRUM_PATCH_PARAMS.n; ++i) { 326 | mc.channelCC[ch][DRUM_PATCH_PARAMS[i]] = randomMidiValue(); 327 | mc.notes.Mute[ch] = randomMidiValue(); 328 | mc.notes.Trigger[ch] = randomMidiValue(); 329 | } 330 | }; 331 | mc.improvedCCScaling = randomBool(); 332 | mc.midiCCAutomates = randomBool(); 333 | mc.midiCCOnSelectedChannel = randomBool(); 334 | mc.midiNotesSelectChannel = randomBool(); 335 | mc.midiReceiveChannel = (if ((rnd.nextInt() & 1) != 0) ((rnd.nextInt() & 15) + 1) else void); 336 | mc.midiTransmitChannel = (if ((rnd.nextInt() & 1) != 0) ((rnd.nextInt() & 15) + 1) else void); 337 | for (i = 0; i < GLOBAL_PARAM_COUNT; ++i) if (PARAMS[i]{:5} != 'Mute.') mc.globalCC[PARAMS[i]] = randomMidiValue(); 338 | for (i = 1; i <= PROGRAM_COUNT; ++i) mc.notes.Program[i] = randomMidiValue(); 339 | mc.notes.Start = randomMidiValue(); 340 | mc.notes.Stop = randomMidiValue(); 341 | for (ptn = 'a'; ptn <= LAST_PATTERN; ptn = succChar(ptn)) mc.notes.Pattern[ptn] = randomMidiValue(); 342 | mc.patternsSendMidi = randomBool(); 343 | mc.pitchWheelRange = 19; 344 | mc.pitchedMode = randomBool(); 345 | mc.supportMidiNoteOff = randomBool(); 346 | mc.supportMidiProgramChange = randomBool(); 347 | mc.patternNoteMode = MODE_NAMES[randomInt() & 3]; 348 | setElement('midiConfig', @mc); 349 | getElement('midiConfig', @mc2); 350 | s = marshal('midiConfig', @mc2); 351 | assert(> isMarshaledFormat('midiConfig', s)); 352 | unmarshal('midiConfig', s, @mc3); 353 | foreach(@mc, >{ 354 | elem = $1; 355 | assert(> mc[elem] == mc2[elem]); 356 | assert(> mc2[elem] == mc3[elem]); 357 | }); 358 | }; 359 | 360 | display('All tests successful. Congrats!'); 361 | 362 | }(); 363 | -------------------------------------------------------------------------------- /legacy/help/arrays.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | PikaScript Library Reference: arrays 7 | 8 | 9 | 10 |
11 |

arrays

12 |

append, compose, copy, decompose, equal, fill, inject, insert, iterate, qsort, remove, rsort, sort

13 |
14 | 15 |
16 |

append

17 |

Syntax

18 |
@array = append(@array, [<elements>, ...])
19 |

Description

20 |

Appends <elements> to @array. If [@array].n does not exist it will be initialized to 0 and this routine will in practice work like compose(). Unlike compose() however, all element argument must be present. The returned value is the input @array reference.

Notice that calling this function on a "double-ended queue" also works.

21 |

Examples

append(@myArray, 5, 6, 7, 8)
equal(append(compose(@temp1, 'a', 'b', 'c'), 'd', 'e', 'f'), compose(@temp2, 'a', 'b', 'c', 'd', 'e', 'f')) == true
22 |

See Also

compose, insert

23 |
24 |
25 | 26 |
27 |

compose

28 |

Syntax

29 |
@array = compose(@array, [<elements>, ...])
30 |

Description

31 |

Creates an array of indexed elements under @array initialized with the values of the remaining arguments (<element>). The first element will have an index of zero (e.g. "array[0]"). The special element 'n' (e.g. "array.n") will contain the number of indexed elements in the array. If an element argument is omitted the corresponding element will not be initialized, possibly making the array "non-contiguous". The returned value is the input @array reference.

Notice that this function does not erase any existing elements under @array. You may want to consider calling prune() on @array before composing a new array.

32 |

Examples

compose(@myArray, 1, 2, 3, 4)
compose(@holy, 'nextIsEmpty', , 'previousWasEmpty')
[compose(@temp, 'zero', 'one', 'two', 'three')][2] === 'two'
33 |

See Also

append, decompose, map, prune

34 |
35 |
36 | 37 |
38 |

copy

39 |

Syntax

40 |
@target = copy(@source, +offset, +count, @target, +index)
41 |

Description

42 |

Copies +count elements from the @source array beginning at +offset into @target at +index, replacing any already existing elements at the target indices. The element count of the @target array (i.e. [@target].n) may be incremented to fit the new elements.

The @source array must be contiguous. If the output +index is greater than [@target].n (or (+index) + (+count) < 0), the resulting array will become non-contiguous.

Only direct elements under the arrays will be affected. Any sub-elements that they in turn may have are ignored. @source and @target may reference the same array. The returned value is the input @target reference.

43 |

Examples

copy(@myArray, 10, 5, @myArray, 13)
equal(copy(compose(@temp1, 'a', 'b', 'c', 'd'), 1, 2, compose(@temp2, 'e', 'f', 'g', 'h'), 3), compose(@temp3, 'e', 'f', 'g', 'b', 'c')) == true
44 |

See Also

clone, inject, remove

45 |
46 |
47 | 48 |
49 |

decompose

50 |

Syntax

51 |
decompose(@array, [@variables, ...])
52 |

Description

53 |

Decomposes an array by storing the indexed elements under @array one by one into the given references. If an argument is left empty, the corresponding element index will be skipped.

54 |

Examples

decompose(@breakMe, @first, @second, @third, , @noFourthButFifth)
55 |

See Also

compose

56 |
57 |
58 | 59 |
60 |

equal

61 |

Syntax

62 |
?same = equal(@arrayA, @arrayB)
63 |

Description

64 |

Returns true if the arrays @arrayA and @arrayB are the same size and all their elements are identical. Both arrays must be contiguous (i.e. all their elements must be defined). Only direct elements under the arrays will be tested. Any sub-elements that they in turn may have are silently ignored.

65 |

Examples

equal(@firstArray, @secondArray)
equal(compose(@temp1, 1, 10, 100, 'one thousand'), compose(@temp2, 1, 10, 100, 'one thousand')) == true
66 | 67 |
68 |
69 | 70 |
71 |

fill

72 |

Syntax

73 |
@array = fill(@array, +offset, +count, <value>)
74 |

Description

75 |

Fills a range of +count elements in @array with <value> starting at +offset, replacing any existing elements. If the target @array does not exist (i.e. [@array].n is not defined) it is created. The element count (i.e. [@array].n) may be incremented to fit the new elements.

Only direct elements under the arrays will be affected. The returned value is the input @array reference.

76 |

Examples

equal(fill(@a, 0, 5, 'x'), compose(@b, 'x', 'x', 'x', 'x', 'x'))
77 |

See Also

copy, inject, insert, remove

78 |
79 |
80 | 81 |
82 |

inject

83 |

Syntax

84 |
@target = inject(@source, +offset, +count, @target, +index)
85 |

Description

86 |

Inserts +count elements from the @source array beginning at +offset into @target at +index, relocating any elements at and after +index to make room for the inserted elements. Both arrays must be contiguous and the target +index must be between 0 and [@target].n. Only direct elements under the arrays will be affected. Any sub-elements that they in turn may have are ignored. @source and @target should not reference the same array. The returned value is the input @target reference.

87 |

Examples

inject(@myArray, 10, 5, @myArray, 13)
equal(inject(compose(@temp1, 'a', 'b', 'c', 'd'), 1, 2, compose(@temp2, 'e', 'f', 'g', 'h'), 3), compose(@temp3, 'e', 'f', 'g', 'b', 'c', 'h')) == true
88 |

See Also

copy, fill, insert, remove

89 |
90 |
91 | 92 |
93 |

insert

94 |

Syntax

95 |
@array = insert(@array, +offset, [<elements>, ...])
96 |

Description

97 |

Inserts one or more elements into @array before the index +offset. The array must be contiguous. Only direct elements under the array will be moved to make room for the new elements. Any sub-elements that they in turn may have remain unaffected. +offset must be between 0 and the element count of @array (or an exception will be thrown). [@array].n must be defined prior to calling this routine. The returned value is the input @array reference.

98 |

Examples

insert(@myArray, 10, 'insert', 'three', 'strings')
equal(insert(compose(@temp1, 'a', 'b', 'f'), 2, 'c', 'd', 'e'), compose(@temp2, 'a', 'b', 'c', 'd', 'e', 'f')) == true
99 |

See Also

inject, remove

100 |
101 |
102 | 103 |
104 |

iterate

105 |

Syntax

106 |
iterate(@array, >doThis)
107 |

Description

108 |

Iterates all elements in @array (as determined by [@array].n) and calls >doThis once for every encountered element in ascending index order. Three arguments will be passed to >doThis:

$0 will be the full reference to the found element (e.g. "::highscores.3")
$1 will be the element index (e.g. 3)
$2 will be the value of the element.

iterate() is the equivalent to foreach() for arrays. Any change to [@array].n while running iterate() will not be accounted for. The array must be contiguous. Only direct elements under the array will be iterated.

109 |

Examples

iterate(compose(@a, 0, 'one', 2, true), >print($1 # '=' # $2))
110 |

See Also

foreach

111 |
112 |
113 | 114 |
115 |

qsort

116 |

Syntax

117 |
qsort(+from, +to, >compare, >swap)
118 |

Description

119 |

This is an abstract implementation of the quicksort algorithm. qsort() handles the logic of the sorting algorithm (the bones) while you provide the functions >compare and >swap that carries out the concrete operations on the data being sorted (the meat).

+from and +to defines the sorting range (+to is non-inclusive).

>compare is called with two sorting indices and you should return a negative value if the data for the first index ($0) should be placed before the data for the second index ($1). Return a positive non-zero value for the opposite and return zero if the data is identical. (You can use the global ::compare function to easily implement this.)

>swap is also called with two indices in $0 and $1 ($0 is always less than $1). The function should swap the data for the two indices. (You can use the global ::swap function to easily implement this.)

The functions sort() and rsort() use this function to implement sorting of entire arrays (ascending and descending respectively).  

120 |

Examples

qsort(0, myArray.n, >myArray[$0] - myArray[$1], >swap(@myArray[$0], @myArray[$1]))
qsort(0, scrambleMe.n, >random(2) - 1, >swap(@scrambleMe[$0], @scrambleMe[$1]))
121 |

See Also

compare, rsort, sort

122 |
123 |
124 | 125 |
126 |

remove

127 |

Syntax

128 |
@array = remove(@array, +offset, [+count = 1])
129 |

Description

130 |

Removes +count number of elements from @array beginning at +offset, relocating any elements after the removed elements so that the array remains contiguous. (Only direct elements under the array are moved. Any sub-elements under these elements will be left untouched.)

If +offset and / or +count are negative, this function still yields predictable results (e.g. an +offset of -3 and +count of 6 will remove the three first elements). Likewise, it is allowed to remove elements beyond the end of the array (but naturally it will have no effect). The returned value is the input @array reference.

131 |

Examples

remove(@removeNumberThree, 3)
remove(@drop1and2, 1, 2)
equal(remove(compose(@temp1, 'a', 'b', 'c', 'd', 'e'), 1, 3), compose(@temp2, 'a', 'e')) == true
132 |

See Also

copy, fill, inject, insert, prune

133 |
134 |
135 | 136 |
137 |

rsort

138 |

Syntax

139 |
@array = rsort(@array)
140 |

Description

141 |

Sorts the elements of @array in descending order. The returned value is the input @array reference. To sort in ascending order, use sort(). If you need greater control over the sorting (e.g. how elements are compared), use the lower level function qsort() instead.

142 |

Examples

rsort(@myArray)
equal(rsort(compose(@temp1, 1.1, -5, 1.5, 17, 0x10, 'xyz', 'a', 'def', 'a')), compose(@temp2, 'xyz', 'def', 'a', 'a', 17, 0x10, 1.5, 1.1, -5)) == true
143 |

See Also

qsort, sort

144 |
145 |
146 | 147 |
148 |

sort

149 |

Syntax

150 |
@array = sort(@array)
151 |

Description

152 |

Sorts the elements of @array in ascending order. The returned value is the input @array reference. To sort in descending order, use rsort(). If you need greater control over the sorting (e.g. how elements are compared), use the lower level function qsort() instead.

153 |

Examples

sort(@myArray)
equal(sort(compose(@temp1, 1.1, -5, 1.5, 17, 0x10, 'xyz', 'a', 'def', 'a')), compose(@temp2, -5, 1.1, 1.5, 0x10, 17, 'a', 'a', 'def', 'xyz')) == true
154 |

See Also

qsort, rsort

155 |
156 |
157 | 158 | 159 | 160 | 161 | -------------------------------------------------------------------------------- /legacy/help/containers.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | PikaScript Library Reference: containers 7 | 8 | 9 | 10 |
11 |

containers

12 |

ascend, clone, foreach, map, prune, redotify, set, undotify

13 |
14 | 15 |
16 |

ascend

17 |

Syntax

18 |
@parent = ascend(@child)
19 |

Description

20 |

Returns a reference to the "parent container" of @child (i.e. the variable or element that contains the sub-element referred to by @child). If @child is a top-level variable, void is returned.

21 |

Examples

ascend(@x['3']) === @x
ascend(@x.y.z) === @x.y
ascend(@x) === void
22 | 23 |
24 |
25 | 26 |
27 |

clone

28 |

Syntax

29 |
@target = clone(@source, @target)
30 |

Description

31 |

Makes a "deep copy" of the container @source to @target, meaning that all elements under the source and any sub-elements that they may have (and so on) will be copied to the target. If there is a variable directly at @source it will also be copied to @target. The returned value is the input @target reference.

Notice that this function does not erase any existing elements under @target. You may want to consider calling prune() on @target first.

32 |

Examples

clone(@myCarbonCopy, @originalData)
33 |

See Also

copy, prune

34 |
35 |
36 | 37 |
38 |

<foreach>

39 |

Syntax

40 |
foreach(@map, >doThis)
41 |

Description

42 |

Traverses all elements under @map (and any sub-elements that they may have and so on) and calls >doThis once for every encountered element. (An alternative description of foreach() is that it calls >doThis for every found variable that begins with the value of @map # '.') Three arguments will be passed to >doThis:

$0 will be the full reference to the found element (e.g. "::zoo.elephant")
$1 will be the name of the element (e.g. "elephant")
$2 will be the value of the element.

The order with which elements are processed is undefined and depends on the implementation of PikaScript. Any modifications to @map while running foreach() will not be reflected in the calls to >doThis. Notice that you normally would not use foreach() on arrays since it would also include the 'n' element (the element count). Use iterate() or a simple for-loop instead.

43 |

Examples

foreach(map(@a, 'Asia', 4157, 'Africa', 1030, 'Americas', 929, 'Europe', 739, 'Oceania', 35), >print($1 # '=' # $2))
44 |

See Also

iterate

45 |
46 |
47 | 48 |
49 |

map

50 |

Syntax

51 |
@map = map(@map, ['keys', <values>, ...])
52 |

Description

53 |

Creates a "map" under @map by assigning sub-elements to @map for each key / value pair passed to the function. The returned value is the input @map reference.

Notice that this function does not erase any existing elements under @map so you may call this function repeatedly to incrementally build a map. Use prune on @map to delete it.

A creative use of this function is to create efficient "switch statements" something that is otherwise missing in PikaScript by mapping keys to functions / lambda expressions. You could then execute the switch like this: mySwitch[theKey].

54 |

Examples

map(@userInfo['magnus'], 'fullName','Magnus Lidstroem' , 'birthDate','31 march 1972' , 'favoriteColor','#3333FF')
map(@actions, 'hi',>print('Good day sir!') , 'spin',>{ for (i = 0; i < 360; ++i) print('Spun ' # i # ' degrees') } , 'quit',>doQuit = true)
[map(@temp, 'zero',0 , 'one',1 , 'two',2 , 'three',3)]['two'] == 2
55 |

See Also

foreach, prune, set

56 |
57 |
58 | 59 |
60 |

prune

61 |

Syntax

62 |
+count = prune(@reference)
63 |

Description

64 |

Deletes the variable referenced to by @reference as well as all its sub-elements. Use prune() to delete an entire "plain old data" container (e.g. an "array" or "map"). Use destruct() instead for deleting an "object" to have its destructor called before it is deleted. prune() returns the number of variables that were deleted.

65 |

Examples

prune(@myArray)
66 |

See Also

delete, destruct

67 |
68 |
69 | 70 |
71 |

redotify

72 |

Syntax

73 |
'yesdots' = redotify('nodots')
74 |

Description

75 |

Decodes an "undotified" string as returned from undotify(). See help for "undotify" for further explanation and examples.

76 |

Examples

redotify('nearly 50%25 use google%2ecom daily') === 'nearly 50% use google.com daily'
77 |

See Also

undotify

78 |
79 |
80 | 81 |
82 |

set

83 |

Syntax

84 |
@set = set(@set, ['keys', ...])
85 |

Description

86 |

Creates a "set" under @set by assigning sub-elements with the value true for each key. The returned value is the input @set reference.

Notice that this function does not erase any existing elements under @set so you may call this function repeatedly to incrementally build a set. Use prune() on @set to delete it.

One practical use for sets is to efficiently check if a value belongs to a group of values. Initially you create the group of values with this function and later you can call exists(@set[key]).

87 |

Examples

set(@validColors, 'red', 'green', 'blue', 'yellow')
exists(@[set(@smallPrimes, 2, 3, 5, 7, 11, 13, 17, 19)][13])
88 |

See Also

foreach, map, prune

89 |
90 |
91 | 92 |
93 |

undotify

94 |

Syntax

95 |
'nodots' = undotify('yesdots')
96 |

Description

97 |

Simply returns a copy of 'source' where all '.' have been replaced with '%2e' and all '%' have been replaced with '%25'. The purpose of this function is to allow arbitrary strings to work as keys in multi-dimensional arrays / deep containers. Without "undotifying" keys, any '.' in the keys would be interpreted as separators. E.g. "files['name.ext'].size" is the same as "files.name.ext.size", which is probably not what you want. Instead use "files[undotify('name.ext')].size". To return the original key from an "undotified" key, use redotify().

98 |

Examples

undotify('nearly 50% use google.com daily') === 'nearly 50%25 use google%2ecom daily'
redotify(undotify('a.b.c%d.e.f')) === 'a.b.c%d.e.f'
99 |

See Also

redotify

100 |
101 |
102 | 103 | 104 | 105 | 106 | -------------------------------------------------------------------------------- /legacy/help/debug.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | PikaScript Library Reference: debug 7 | 8 | 9 | 10 |
11 |

debug

12 |

assert, trace

13 |
14 | 15 |
16 |

assert

17 |

Syntax

18 |
assert(?testResult | >testMe, ['description'])
19 |

Description

20 |

Asserts are used to check for programming errors in run-time. Until you run "debug.pika", asserts are disabled which means this function will do absolutely nothing (it is defined as an empty function in "stdlib.pika"). Running "debug.pika" will enable asserts by redefining this function. When enabled, it either checks the boolean ?testResult or executes >testMe and checks the result.

Two things differ depending on the choice of passing a boolean or a function / lambda expression. If you pass a boolean, e.g. assert(myfunc() == 3), and assertions are disabled, the argument will still be evaluated, i.e. myfunc() will still be called. Furthermore, if 'description' is omitted, the exception on an assertion failure will simply contain 'true' or 'false'.

If you pass a function / lambda expression, e.g. assert(>myfunc() == 3), the argument will only be evaluated if assertions are enabled and the exception will contain the full expression. In most cases you will want to use this variant.

21 |

Examples

assert(>(0 <= $0 <= 100))
assert(alwaysCallMe(), 'alwaysCallMe() failed miserably')
22 | 23 |
24 |
25 | 26 |
27 |

<trace>

28 |

Syntax

29 |
trace([>tracer], [+level = 2])
30 |

Description

31 |

Sets or resets the tracer function. The tracer function is called at various points in the PikaScript interpreter code. For example, you can use it for tracing caught exceptions, function calls and even implement debuggers and profilers.

+level ranges from 0 (no tracing) to 21 (maximum tracing) and determines which events that will trigger a callback. The default trace level of 2 calls the trace function on each function entry and exit. Other useful levels are 1 for tracing caught errors and 3 to trace every interpreted statement. (Please see "PikaScriptImpl.h" for a complete listing of all levels.)

The >tracer function will be called with the following arguments:

$0 = the source code being executed
$1 = the offset into the source code
$2 = whether $3 is an lvalue or an rvalue (lvalue = identifier, rvalue = actual value)
$3 = the result from the last operation
$4 = trace level
$5 = false for "entry", true for "exit" (e.g. function call entry / exit).

Call trace() without arguments to stop all tracing.

32 |

Examples

trace()
trace(function { print((if ($5) '} ' else '{ ') # if (exists(@^$callee)) ^$callee else '????') })
33 | 34 |
35 |
36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /legacy/help/debugging.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | PikaScript Library Reference: debugging 7 | 8 | 9 | 10 |
11 |

debugging

12 |

assert, trace

13 |
14 | 15 |
16 |

assert

17 |

Syntax

18 |
assert(?testResult | >testMe, ['description'])
19 |

Description

20 |

Asserts are used to check for programming errors in run-time. Until you run "debug.pika", asserts are disabled which means this function will do absolutely nothing (it is defined as an empty function in "stdlib.pika"). Running "debug.pika" will enable asserts by redefining this function. When enabled, it either checks the boolean ?testResult or executes >testMe and checks the result.

Two things differ depending on the choice of passing a boolean or a function / lambda expression. If you pass a boolean, e.g. assert(myfunc() == 3), and assertions are disabled, the argument will still be evaluated, i.e. myfunc() will still be called. Furthermore, if 'description' is omitted, the exception on an assertion failure will simply contain 'true' or 'false'.

If you pass a function / lambda expression, e.g. assert(>myfunc() == 3), the argument will only be evaluated if assertions are enabled and the exception will contain the full expression. In most cases you will want to use this variant.

21 |

Examples

assert(>(0 <= $0 <= 100))
assert(alwaysCallMe(), 'alwaysCallMe() failed miserably')
22 | 23 |
24 |
25 | 26 |
27 |

<trace>

28 |

Syntax

29 |
trace([>tracer], [+level = 2])
30 |

Description

31 |

Sets or resets the tracer function. The tracer function is called at various points in the PikaScript interpreter code. For example, you can use it for tracing caught exceptions, function calls and even implement debuggers and profilers. +level ranges from 0 (no tracing) to 21 (maximum tracing) and determines which events that will trigger a callback. The default trace level of 2 calls the trace function on each function entry and exit. Other useful levels are 1 for tracing caught errors and 3 to trace every interpreted statement. (Please see the PikaScriptImpl.h file for a complete listing of all levels.)

The >tracer function will be called with the following arguments:

$0 = the source code being executed
$1 = the offset into the source code
$2 = whether $3 is an lvalue or an rvalue (lvalue = identifier, rvalue = actual value)
$3 = the result from the last operation
$4 = trace level
$5 = false for "entry", true for "exit" (e.g. function call entry / exit).

Call trace() without arguments to stop all tracing.

32 |

Examples

trace()
trace(function { print((if ($5) '} ' else '{ ') # if (exists(@^$callee)) ^$callee else '????') })
33 | 34 |
35 |
36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /legacy/help/help.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | PikaScript Library Reference: help 7 | 8 | 9 | 10 |
11 |

help

12 |

describe, help

13 |
14 | 15 |
16 |

describe

17 |

Syntax

18 |
describe('category', 'page', 'syntax', ['description'], ['examples'], ['seealso'])
19 |

Description

20 |

Adds a help page to the database.

21 |

Examples

describe('#mine', 'countIf', '+count = countIf(@array, <value>)', 'Counts the number of items in @array that is equal to <value>.', "n = countIf(@fruits, 'apple')")
22 | 23 |
24 |
25 | 26 |
27 |

help

28 |

Syntax

29 |
help('page' | '/search')
30 |

Description

31 |

Prints a help page or searches the help database for text. Function syntax is documented with the following conventions:

- Arguments in [ ] brackets are optional and default values may be documented like this: [arg = value]
- Vertical bar | is used to separate alternatives
- ... means repeat 0 or more times
- "Type classes" can be identified as follows: ?boolean, +number, 'string', >function, @reference, <arbitrary>

Type help('#categories') for a list of valid categories. help('#pages') lists all available help pages. You can also search the entire help database for a string with help('/search')

32 |

Examples

help('#categories')
help('#pages')
help('#utils')
help('args')
help('/delete')
33 | 34 |
35 |
36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /legacy/help/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | PikaScript Library Reference 7 | 8 | 9 |

PikaScript Library Reference

10 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /legacy/help/objects.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | PikaScript Library Reference: objects 7 | 8 | 9 | 10 |
11 |

objects

12 |

construct, destruct, gc, invokeMethod, method, new, newLocal, this

13 |
14 | 15 |
16 |

construct

17 |

Syntax

18 |
@object = construct(@object, >constructor, [<arguments>, ...])
19 |

Description

20 |

Constructs

21 | 22 |

See Also

destruct, new, newLocal, this

23 |
24 |
25 | 26 |
27 |

destruct

28 |

Syntax

29 |
+count = destruct(@object)
30 |

Description

31 |

Destructs

32 | 33 |

See Also

construct, delete, prune

34 |
35 |
36 | 37 |
38 |

gc

39 |

Syntax

40 |
+count = gc()
41 |

Description

42 |

Garbage collect.

43 | 44 |

See Also

new, newLocal

45 |
46 |
47 | 48 |
49 |

invokeMethod

50 |

Syntax

51 |
<result> = invokeMethod(@object, 'method', @args, [+offset = 0], [+count])
52 |

Description

53 |

Like invoke() but for methods.

54 | 55 |

See Also

invoke

56 |
57 |
58 | 59 |
60 |

method

61 |

Syntax

62 |
'method' = method()
63 |

Description

64 |

Method called.

65 | 66 |

See Also

this

67 |
68 |
69 | 70 |
71 |

new

72 |

Syntax

73 |
@object = new(>constructor, [<arguments>, ...])
74 |

Description

75 |

Allocates and constructs.

76 | 77 |

See Also

construct, gc, newLocal

78 |
79 |
80 | 81 |
82 |

newLocal

83 |

Syntax

84 |
@object = newLocal(>constructor, [<arguments>, ...])
85 |

Description

86 |

Allocates and constructs on local heap.

87 | 88 |

See Also

construct, gc, new

89 |
90 |
91 | 92 |
93 |

this

94 |

Syntax

95 |
@object = this()
96 |

Description

97 |

Object called.

98 | 99 |

See Also

method

100 |
101 |
102 | 103 | 104 | 105 | 106 | -------------------------------------------------------------------------------- /legacy/help/queues.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | PikaScript Library Reference: queues 7 | 8 | 9 | 10 |
11 |

queues

12 |

popBack, popFront, pushBack, pushFront, queueSize, resetQueue

13 |
14 | 15 |
16 |

popBack

17 |

Syntax

18 |
<value> = popBack(@queue)
19 |

Description

20 |

Pops <value> from the back of the double-ended queue @queue. If @queue is empty an exception will be thrown. (@queue must have been initialized with resetQueue() prior to calling this routine.)

21 |

Examples

lastIn = popBack(@dq)
22 |

See Also

popFront, pushBack, pushFront, queueSize, resetQueue

23 |
24 |
25 | 26 |
27 |

popFront

28 |

Syntax

29 |
<value> = popFront(@queue)
30 |

Description

31 |

Pops <value> from the front of the double-ended queue @queue. If @queue is empty an exception will be thrown. (@queue must have been initialized with resetQueue() prior to calling this routine.)

32 |

Examples

firstOut = popFront(@dq)
33 |

See Also

popBack, pushBack, pushFront, queueSize, resetQueue

34 |
35 |
36 | 37 |
38 |

pushBack

39 |

Syntax

40 |
@queue = pushBack(@queue, <value>)
41 |

Description

42 |

Pushes <value> to the back of the double-ended queue @queue. The returned value is the input @queue reference. (@queue must have been initialized with resetQueue() prior to calling this routine.)

It is also legal to call append() to push several elements at once to a queue.

43 |

Examples

pushBack(@dq, 'lastIn')
44 |

See Also

append, popBack, popFront, pushFront, queueSize, resetQueue

45 |
46 |
47 | 48 |
49 |

pushFront

50 |

Syntax

51 |
@queue = pushFront(@queue, <value>)
52 |

Description

53 |

Pushes <value> to the front of the double-ended queue @queue. The returned value is the input @queue reference. (@queue must have been initialized with resetQueue() prior to calling this routine.)

54 |

Examples

pushFront(@dq, 'firstOut')
55 |

See Also

popBack, popFront, pushBack, queueSize, resetQueue

56 |
57 |
58 | 59 |
60 |

queueSize

61 |

Syntax

62 |
+count = queueSize(@queue)
63 |

Description

64 |

Returns the count of elements in the double-ended queue @queue. The count is defined by [@queue].n - [@queue].m (see resetQueue() for an explanation). (@queue must have been initialized with resetQueue() prior to calling this routine.)

65 |

Examples

count = queueSize(@dq)
66 |

See Also

popBack, popFront, pushBack, pushFront, resetQueue

67 |
68 |
69 | 70 |
71 |

resetQueue

72 |

Syntax

73 |
resetQueue(@queue)
74 |

Description

75 |

Initializes the "double-ended queue" referenced to by @queue for use with pushBack(), popFront() etc by setting the sub-elements [@queue].m and [@queue].n to 0.

[@queue].m is the index of the first element on the queue and it is decremented on pushFront() and incremented on popFront(). [@queue].n is one greater than the index of the last element on the queue and it is incremented on pushBack() and decremented on popBack(). (The 'm' and 'n' identifiers were chosen to make queue() compatible with some of the array functions such as append().)

76 |

Examples

resetQueue(@dq)
77 |

See Also

popBack, popFront, pushBack, pushFront, queueSize

78 |
79 |
80 | 81 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /legacy/help/strings.html: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malstrom72/microtonic-scripts-sdk/90d8465f350b939feb102718a0cee1a6a903a767/legacy/help/strings.html -------------------------------------------------------------------------------- /legacy/help/utilities.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | PikaScript Library Reference: utilities 7 | 8 | 9 | 10 |
11 |

utilities

12 |

args, classify, coalesce, compare, default, delete, evaluate, exists, input, invoke, load, max, min, parse, print, run, save, swap, throw, time, try, vargs

13 |
14 | 15 |
16 |

args

17 |

Syntax

18 |
args([@variables, ...])
19 |

Description

20 |

Assigns arguments to named variables. Pass a reference to a local variable for each argument your function expects. The caller of your function must pass exactly this number of arguments or an exception will be thrown.

21 |

Examples

args(@x, @y)
22 |

See Also

vargs

23 |
24 |
25 | 26 |
27 |

<classify>

28 |

Syntax

29 |
'class' = classify(<value>)
30 |

Description

31 |

Examines <value> and tries to determine what "value class" it belongs to:

- 'void' (empty string)
- 'boolean' (true or false)
- 'number' (starts with a digit, '-' or 'i' for "infinity", and is convertible to a number)
- 'reference' (starting with ':' and containing at least one more ':')
- 'function' (enclosed in '{ }' or begins with '>')
- 'native' (enclosed in '< >')
- 'string' (if no other match)

32 |

Examples

classify(void) == 'void'
classify('false') == 'boolean'
classify(123.456) == 'number'
classify(@localvar) == 'reference'
classify(function { }) == 'function'
classify(>lambda) == 'function'
classify('<print>') == 'native'
classify('tumbleweed') == 'string'
33 | 34 |
35 |
36 | 37 |
38 |

coalesce

39 |

Syntax

40 |
<value> = coalesce(<values> | @variables, ...)
41 |

Description

42 |

Returns the first <value> in the argument list that is non-void, or the contents of the first @variables that exists (whichever comes first).

43 |

Examples

coalesce(@mustBeDefined, '')
coalesce(cantBeEmpty, perhapsThisAintEmpty, 'nowIAmDefinitelyNotEmpty')
44 |

See Also

default, exists

45 |
46 |
47 | 48 |
49 |

compare

50 |

Syntax

51 |
<diff> = compare(<a>, <b>)
52 |

Description

53 |

Returns 0 if <a> equals <b>, -1 if <a> is less than <b> and 1 if <a> is greater than <b>. This function is useful in sorting algorithms.

54 |

Examples

compare('abc', 'def') < 0
compare('def', 'abc') > 0
compare('abc', 'abc') == 0
55 |

See Also

qsort, swap

56 |
57 |
58 | 59 |
60 |

default

61 |

Syntax

62 |
default(@variable, <value>)
63 |

Description

64 |

Assigns <value> to @variable if @variable does not exist. If it does already exist, this function does nothing. Use this function for example to initialize optional arguments.

65 |

Examples

default(@name, 'Smith')
66 |

See Also

coalesce

67 |
68 |
69 | 70 |
71 |

<delete>

72 |

Syntax

73 |
delete(@variable)
74 |

Description

75 |

Deletes the variable referenced to by @variable.

Notice that this function can only delete a single variable at a time. This means only a single "element" in a "container" as well. Use prune() to delete an entire "plain old data" container and destruct() to delete an object.

76 |

Examples

delete(@begone)
delete(@hurray[1972])
77 |

See Also

destruct, exists, prune

78 |
79 |
80 | 81 |
82 |

<evaluate>

83 |

Syntax

84 |
<result> = evaluate('code', [@frame])
85 |

Description

86 |

Evaluates 'code' and returns the result. You can decide which frame should execute the code by supplying a reference in @frame. Without @frame, code is executed in its own frame just as if you would call a function. Only the "frame identifier" of @frame is used, so you may for example pass a single ^ to evaluate code in the caller's frame.

87 |

Examples

evaluate('3 + 3') == 6
evaluate('x = random(1)', @x)
88 |

See Also

expand, invoke, parse, run

89 |
90 |
91 | 92 |
93 |

<exists>

94 |

Syntax

95 |
?found = exists(@variable)
96 |

Description

97 |

Returns true if the variable referenced to by @variable is defined.

98 |

Examples

exists(@::aglobal)
exists(@users['magnus lidstrom'])
99 |

See Also

coalesce, default, delete

100 |
101 |
102 | 103 |
104 |

<input>

105 |

Syntax

106 |
'answer' = input('question')
107 |

Description

108 |

Prints 'question' and returns a string read from standard input.

109 |

Examples

name = input("What's your name? ")
110 |

See Also

print

111 |
112 |
113 | 114 |
115 |

<invoke>

116 |

Syntax

117 |
invoke(['callee'], [>body], @args, [+offset = 0], [+count])
118 |

Description

119 |

Calls 'callee' (or >body) with the argument list @args. The difference between using 'callee' or >body is that the former should be a string with a function name, while the latter should be an actual function body. If both arguments are present, >body will be executed, but the called function's $callee variable will be set to 'callee'.

+offset can be used to adjust the element index for the first argument. +count is the number of arguments. If it is omitted, [@args].n is used to determine the count.

120 |

Examples

invoke('max', , @values)
invoke('(callback)', $0, @$, 1, 4)
121 |

See Also

evaluate, run

122 |
123 |
124 | 125 |
126 |

<load>

127 |

Syntax

128 |
'contents' = load('filePath')
129 |

Description

130 |

Loads a file from disk and returns it as a string. The standard implementation uses the file I/O of the standard C++ library, which takes care of line ending conversion etc. It can normally only handle ASCII text files.

131 |

Examples

data = load('myfolder/myfile.txt')
132 |

See Also

save

133 |
134 |
135 | 136 |
137 |

max

138 |

Syntax

139 |
<m> = max(<x>, <y>, [<z>, ...])
140 |

Description

141 |

Returns the largest value of all the arguments.

142 |

Examples

max(5, 3, 7, 1, 4) == 7
max('Sleepy', 'Grumpy', 'Happy', 'Bashful', 'Dopey', 'Sneezy', 'Doc') == 'Sneezy'
max('Zero', '10', '5') == 'Zero'
143 |

See Also

min

144 |
145 |
146 | 147 |
148 |

min

149 |

Syntax

150 |
<m> = min(<x>, <y>, [<z>, ...])
151 |

Description

152 |

Returns the smallest value of all the arguments.

153 |

Examples

min(5, 3, 7, 1, 4) == 1
min('Sleepy', 'Grumpy', 'Happy', 'Bashful', 'Dopey', 'Sneezy', 'Doc') == 'Bashful'
min('Zero', '10', '5') == '5'
154 |

See Also

max

155 |
156 |
157 | 158 |
159 |

<parse>

160 |

Syntax

161 |
+offset = parse('code')
162 |

Description

163 |

Parses 'code' (without executing it) and returns the number of characters that was successfully parsed. 'code' is expected to begin with a single PikaScript expression. The parsing ends when a semicolon or any unknown or unexpected character is encountered (including unbalanced parentheses etc). The resulting expression needs to be syntactically correct or an exception will be thrown.

You can use this function to extract PikaScript code inlined in other text.

164 |

Examples

parse('3+3') == 3
parse('1 + 2 * 3 ; stop at semicolon') == 10
parse(' /* leading comment */ code_here /* skip */ /* trailing */ /* comments */ but stop here') == 74
parse('stop after space after stop') == 5
parse('x + x * 3 ) * 7 /* stop at unbalanced ) */') == 10
165 |

See Also

evaluate, run

166 |
167 |
168 | 169 |
170 |

<print>

171 |

Syntax

172 |
print('textLine')
173 |

Description

174 |

Prints 'textLine' to the standard output, appending a newline character. (Sorry, but standard PikaScript provides no means for outputting text without the newline.)

175 |

Examples

print('Hello world!')
176 |

See Also

input

177 |
178 |
179 | 180 |
181 |

run

182 |

Syntax

183 |
run('filePath')
184 |

Description

185 |

Loads and executes a PikaScript source file. The code is executed in its own frame, just as if you were calling a function.

186 |

Examples

run('src/chess.pika')
187 |

See Also

evaluate

188 |
189 |
190 | 191 |
192 |

<save>

193 |

Syntax

194 |
save('filePath', 'contents')
195 |

Description

196 |

Saves 'contents' to a file (replacing any existing file). The standard implementation uses the file I/O of the standard C++ library, which takes care of line ending conversion etc. It can normally only handle ASCII text files.

197 |

Examples

save('myfolder/myfile.txt', 'No, sir, away! A papaya war is on!')
198 |

See Also

load

199 |
200 |
201 | 202 |
203 |

swap

204 |

Syntax

205 |
swap(@a, @b)
206 |

Description

207 |

Swaps the contents of the variables referenced to by @a and @b. This function is useful in sorting algorithms.

208 |

Examples

swap(@master, @slave)
209 |

See Also

compare, qsort

210 |
211 |
212 | 213 |
214 |

<throw>

215 |

Syntax

216 |
throw('error')
217 |

Description

218 |

Throws an exception. 'error' should describe the error in human readable form. Use try() to catch errors. (PikaScript exceptions are standard C++ exceptions. How uncaught exceptions are handled is up to the host application.)

219 |

Examples

throw('Does not compute')
220 |

See Also

try

221 |
222 |
223 | 224 |
225 |

<time>

226 |

Syntax

227 |
+secs = time()
228 |

Description

229 |

Returns the system clock as the number of seconds passed since January 1 1970 (or at least, if that is how the C time() function works on your platform).

230 |

Examples

elapsed = time() - lastcheck
231 | 232 |
233 |
234 | 235 |
236 |

<try>

237 |

Syntax

238 |
<result> = try(>doThis)
239 |

Description

240 |

Executes >doThis, catching any thrown exceptions and returning the error string of the exception. If no exception was caught, void is returned. The returned value of >doThis is discarded. (PikaScript exceptions are standard C++ exceptions. You may catch other exceptions than PikaScript errors with this function.)

241 |

Examples

success = try(>data = load(file))
try(>1+1) == void
try(>1+'a') == "Invalid number: 'a'"
try(>throw('catchme')) == 'catchme'
242 |

See Also

throw

243 |
244 |
245 | 246 |
247 |

vargs

248 |

Syntax

249 |
vargs([@arguments, ...], , [@optionals, ...])
250 |

Description

251 |

As args() but you may define arguments that are optional. The caller of your function must pass all required arguments or an exception will be thrown. An exception will also be thrown if the caller passes more optional arguments than present in vargs(). An easy way to assign default values for optional arguments is with the default() function. Alternatively you may want to use coalesce().

252 |

Examples

vargs(@required1, @required2, , @optional1, @optional2)
253 |

See Also

args, coalesce, default

254 |
255 |
256 | 257 | 258 | 259 | 260 | -------------------------------------------------------------------------------- /tmLanguages/soniccharge/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | // A launch configuration that launches the extension inside a new window 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | { 6 | "version": "0.2.0", 7 | "configurations": [ 8 | { 9 | "name": "Extension", 10 | "type": "extensionHost", 11 | "request": "launch", 12 | "args": [ 13 | "--extensionDevelopmentPath=${workspaceFolder}" 14 | ] 15 | } 16 | ] 17 | } -------------------------------------------------------------------------------- /tmLanguages/soniccharge/.vscodeignore: -------------------------------------------------------------------------------- 1 | .vscode/** 2 | .vscode-test/** 3 | .gitignore 4 | vsc-extension-quickstart.md 5 | -------------------------------------------------------------------------------- /tmLanguages/soniccharge/cushyschema.tmLanguage: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | $schema 6 | https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json 7 | name 8 | cushyschema 9 | scopeName 10 | source.cushyschema 11 | fileTypes 12 | 13 | schema 14 | 15 | patterns 16 | 17 | 18 | name 19 | keyword.control.cushyschema 20 | match 21 | (\(|\)|\[|\]|\||<-|\.\.\.|=|\?(file:)?|{|}|\\|include:|resources:) 22 | 23 | 24 | name 25 | string.quoted.cushyschema 26 | begin 27 | ' 28 | end 29 | ' 30 | 31 | 32 | name 33 | string.quoted.cushyschema 34 | begin 35 | " 36 | end 37 | " 38 | 39 | 40 | name 41 | entity.name.cushyschema 42 | begin 43 | < 44 | end 45 | > 46 | 47 | 48 | name 49 | entity.name.cushyschema 50 | match 51 | (\*|%)([_a-zA-Z$_][a-zA-Z$_0-9]*)? 52 | 53 | 54 | name 55 | entity.name.cushyschema 56 | match 57 | [_a-zA-Z$_][a-zA-Z$_0-9]*\s+<- 58 | 59 | 60 | name 61 | comment.block.cushyschema 62 | begin 63 | /\* 64 | end 65 | \*/ 66 | 67 | 68 | name 69 | comment.line.cushyschema 70 | match 71 | //.*$ 72 | 73 | 74 | name 75 | variable.name.cushyschema 76 | match 77 | [_a-zA-Z_][a-zA-Z_0-9]*: 78 | 79 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /tmLanguages/soniccharge/impd.tmLanguage: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | $schema 6 | https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json 7 | name 8 | impd 9 | scopeName 10 | source.impd 11 | fileTypes 12 | 13 | impd 14 | 15 | patterns 16 | 17 | 18 | include 19 | #impd 20 | 21 | 22 | repository 23 | 24 | impd 25 | 26 | patterns 27 | 28 | 29 | include 30 | #stringEscape 31 | 32 | 33 | include 34 | #string 35 | 36 | 37 | include 38 | #comment 39 | 40 | 41 | include 42 | #group 43 | 44 | 45 | include 46 | #expression 47 | 48 | 49 | include 50 | #assignment 51 | 52 | 53 | include 54 | #variable 55 | 56 | 57 | include 58 | #number 59 | 60 | 61 | include 62 | #boolean 63 | 64 | 65 | include 66 | #instruction 67 | 68 | 69 | include 70 | #label 71 | 72 | 73 | 74 | group 75 | 76 | patterns 77 | 78 | 79 | name 80 | meta.group.impd 81 | begin 82 | \[ 83 | end 84 | \] 85 | patterns 86 | 87 | 88 | include 89 | #impd 90 | 91 | 92 | 93 | 94 | 95 | expression 96 | 97 | patterns 98 | 99 | 100 | name 101 | meta.expression.impd 102 | begin 103 | { 104 | end 105 | } 106 | patterns 107 | 108 | 109 | include 110 | #stringEscape 111 | 112 | 113 | include 114 | #string 115 | 116 | 117 | include 118 | #comment 119 | 120 | 121 | include 122 | #constant 123 | 124 | 125 | include 126 | #variable 127 | 128 | 129 | include 130 | #number 131 | 132 | 133 | include 134 | #function 135 | 136 | 137 | 138 | 139 | 140 | comment 141 | 142 | patterns 143 | 144 | 145 | name 146 | comment.block.documentation.impd 147 | begin 148 | /\*\* 149 | beginCaptures 150 | 151 | 0 152 | 153 | name 154 | punctuation.definition.comment.impd 155 | 156 | 157 | end 158 | \*/ 159 | endCaptures 160 | 161 | 0 162 | 163 | name 164 | punctuation.definition.comment.impd 165 | 166 | 167 | 168 | 169 | name 170 | comment.block.impd 171 | begin 172 | /\* 173 | beginCaptures 174 | 175 | 0 176 | 177 | name 178 | punctuation.definition.comment.impd 179 | 180 | 181 | end 182 | \*/ 183 | endCaptures 184 | 185 | 0 186 | 187 | name 188 | punctuation.definition.comment.impd 189 | 190 | 191 | 192 | 193 | match 194 | //.*(?=\n) 195 | name 196 | comment.line.double-slash.impd 197 | 198 | 199 | 200 | assignment 201 | 202 | patterns 203 | 204 | 205 | name 206 | meta.assignment.impd 207 | match 208 | \b([a-zA-Z$_][a-zA-Z0-9$_]*)\s*=\s* 209 | captures 210 | 211 | 1 212 | 213 | name 214 | entity.name.variable.impd, variable.other.impd 215 | 216 | 217 | 218 | 219 | 220 | label 221 | 222 | patterns 223 | 224 | 225 | name 226 | meta.label.impd 227 | match 228 | \b([a-zA-Z$_][a-zA-Z0-9$_]*)\s*: 229 | captures 230 | 231 | 1 232 | 233 | name 234 | entity.name.label.impd, variable.parameter.impd 235 | 236 | 237 | 238 | 239 | 240 | variable 241 | 242 | patterns 243 | 244 | 245 | name 246 | entity.name.variable.impd, variable.other.impd 247 | match 248 | (\$[a-zA-Z0-9$_.]+) 249 | 250 | 251 | 252 | boolean 253 | 254 | patterns 255 | 256 | 257 | name 258 | constant.language.impd 259 | match 260 | (?i)\b(yes|no)\b 261 | 262 | 263 | 264 | instruction 265 | 266 | patterns 267 | 268 | 269 | name 270 | meta.format.impd 271 | match 272 | (?i)\b(format)\s*(\S*)\s*(requires)\s*:\s*(\S*) 273 | captures 274 | 275 | 1 276 | 277 | name 278 | support.function.impd 279 | 280 | 2 281 | 282 | name 283 | string.other.impd 284 | 285 | 3 286 | 287 | name 288 | entity.name.label.impd, variable.parameter.impd 289 | 290 | 4 291 | 292 | name 293 | string.other.impd 294 | 295 | 296 | 297 | 298 | name 299 | support.function.impd 300 | match 301 | (?i)\b(meta|debug|trace)\b 302 | 303 | 304 | name 305 | meta.assignment.impd 306 | match 307 | (?i)\b(local|return)\s*([a-zA-Z$_][a-zA-Z0-9$_]*)(\s*=\s*)? 308 | captures 309 | 310 | 1 311 | 312 | name 313 | storage.type.impd 314 | 315 | 2 316 | 317 | name 318 | entity.name.variable.impd 319 | 320 | 321 | 322 | 323 | name 324 | keyword.control.impd 325 | match 326 | (?i)\b(if|repeat|for|stop|call|include)\b 327 | 328 | 329 | 330 | number 331 | 332 | patterns 333 | 334 | 335 | name 336 | constant.numeric.hex.impd 337 | match 338 | (?<![a-zA-Z0-9])0x[0-9A-Fa-f]+ 339 | 340 | 341 | name 342 | constant.numeric.impd 343 | match 344 | (?<![a-zA-Z0-9])[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?(\s*%)? 345 | 346 | 347 | 348 | function 349 | 350 | patterns 351 | 352 | 353 | name 354 | support.function.math.impd 355 | match 356 | (?i)\b(abs|acos|asin|atan|ceil|cos|cosh|exp|floor|log|log10|sin|sinh|sqrt|tan|tanh)(?=\() 357 | 358 | 359 | name 360 | support.function.other.impd 361 | match 362 | (?i)\b(def|len)(?=\() 363 | 364 | 365 | 366 | constant 367 | 368 | patterns 369 | 370 | 371 | name 372 | constant.language.impd 373 | match 374 | (?i)\b(pi)\b 375 | 376 | 377 | 378 | string 379 | 380 | patterns 381 | 382 | 383 | name 384 | string.quoted.double.impd 385 | begin 386 | " 387 | end 388 | " 389 | patterns 390 | 391 | 392 | include 393 | #stringEscape 394 | 395 | 396 | 397 | 398 | 399 | stringEscape 400 | 401 | patterns 402 | 403 | 404 | match 405 | \\U[0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f] 406 | name 407 | constant.character.escape.bigint.impd 408 | 409 | 410 | match 411 | \\u[0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f] 412 | name 413 | constant.character.escape.unicode.impd 414 | 415 | 416 | match 417 | \\x[0-9A-Fa-f][0-9A-Fa-f] 418 | name 419 | constant.character.escape.hex.impd 420 | 421 | 422 | match 423 | \\[0-9]+ 424 | name 425 | constant.character.escape.decimal.impd 426 | 427 | 428 | match 429 | \\. 430 | name 431 | constant.character.escape.impd 432 | 433 | 434 | 435 | 436 | 437 | 438 | -------------------------------------------------------------------------------- /tmLanguages/soniccharge/ivg.tmLanguage: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | $schema 6 | https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json 7 | name 8 | ivg 9 | scopeName 10 | source.ivg 11 | fileTypes 12 | 13 | ivg 14 | 15 | patterns 16 | 17 | 18 | name 19 | meta.group.ivg 20 | begin 21 | \[ 22 | end 23 | \] 24 | patterns 25 | 26 | 27 | include 28 | source.ivg 29 | 30 | 31 | 32 | 33 | include 34 | source.impd 35 | 36 | 37 | name 38 | constant.numeric.color.ivg 39 | match 40 | (?<![a-zA-Z0-9])#[0-9A-Fa-f]{6,8} 41 | 42 | 43 | name 44 | constant.numeric.hex.ivg 45 | match 46 | (?<![a-zA-Z0-9])#[0-9A-Fa-f]{2} 47 | 48 | 49 | name 50 | constant.language.colors.ivg 51 | match 52 | (?i)\b(none|aqua|black|blue|fuchsia|gray|green|lime|maroon|navy|olive|purple|red|silver|teal|white|yellow)\b 53 | 54 | 55 | name 56 | constant.language.other.ivg 57 | match 58 | (?i)\b(linear|radial|butt|round|square|bevel|curve|miter|non-zero|even-odd|left|center|right|top|middle|bottom left|center|right)\b 59 | 60 | 61 | name 62 | support.function.color.ivg 63 | match 64 | (?i)\b(rgb|hsv)(?=\() 65 | 66 | 67 | name 68 | support.function.instruction.ivg 69 | match 70 | (?i)\b(rect|line|ellipse)\b 71 | 72 | 73 | name 74 | meta.path.ivg 75 | contentName 76 | meta.group.impd 77 | begin 78 | (?i)\b(PATH)\s((svg):)\s*(\[) 79 | end 80 | (\]) 81 | beginCaptures 82 | 83 | 1 84 | 85 | name 86 | support.function.instruction.ivg 87 | 88 | 2 89 | 90 | name 91 | meta.label.impd 92 | 93 | 3 94 | 95 | name 96 | entity.name.label.impd, variable.parameter.impd 97 | 98 | 4 99 | 100 | name 101 | meta.group.impd 102 | 103 | 104 | endCaptures 105 | 106 | 1 107 | 108 | name 109 | meta.group.impd 110 | 111 | 112 | patterns 113 | 114 | 115 | name 116 | keyword.operator.svg.path.ivg 117 | match 118 | (?i)[MLHVCSQTAZ] 119 | 120 | 121 | name 122 | entity.name.variable.impd, variable.other.impd 123 | match 124 | (\$[a-zA-Z0-9$_.]+) 125 | 126 | 127 | name 128 | constant.numeric.impd 129 | match 130 | [-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?(\s*%)? 131 | 132 | 133 | include 134 | source.impd 135 | 136 | 137 | 138 | 139 | name 140 | support.function.instruction.ivg 141 | match 142 | (?i)\b(bounds|context|options|pen|fill|mask|reset|RECT|ELLIPSE|PATH|STAR|WIPE)\b 143 | 144 | 145 | name 146 | support.function.transformation.ivg 147 | match 148 | (?i)\b(offset|scale|rotate|shear|matrix)\b 149 | 150 | 151 | name 152 | support.function.instruction.ivg 153 | match 154 | (?i)\b(define\s+font|define\s+image|font|TEXT|IMAGE)\b 155 | 156 | 157 | repository 158 | 159 | 160 | 161 | -------------------------------------------------------------------------------- /tmLanguages/soniccharge/ivgfont.tmLanguage: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | $schema 6 | https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json 7 | name 8 | ivgfont 9 | scopeName 10 | source.ivgfont 11 | fileTypes 12 | 13 | ivgfont 14 | 15 | patterns 16 | 17 | 18 | include 19 | source.impd 20 | 21 | 22 | name 23 | meta.instruction.metrics.ivgfont 24 | begin 25 | \b(metrics)\b 26 | end 27 | (?=[; 28 | ]) 29 | captures 30 | 31 | 1 32 | 33 | name 34 | support.function.instruction.ivgfont 35 | 36 | 37 | patterns 38 | 39 | 40 | include 41 | source.impd 42 | 43 | 44 | 45 | 46 | name 47 | meta.instruction.glyph.ivgfont 48 | begin 49 | \b(glyph)\s*(\S+)\s*([0-9]+) 50 | end 51 | (?=[; 52 | ]) 53 | captures 54 | 55 | 1 56 | 57 | name 58 | support.function.instruction.ivgfont 59 | 60 | 2 61 | 62 | name 63 | constant.character.escape.charcode.ivgfont 64 | 65 | 3 66 | 67 | name 68 | constant.numeric.ivgfont 69 | 70 | 71 | contentName 72 | string.other.ivgfont 73 | patterns 74 | 75 | 76 | include 77 | source.impd#stringEscape 78 | 79 | 80 | 81 | 82 | name 83 | meta.instruction.kern.ivgfont 84 | begin 85 | \b(kern)\s*([+-]?[0-9]+) 86 | end 87 | (?=[; 88 | ]) 89 | captures 90 | 91 | 1 92 | 93 | name 94 | support.function.instruction.ivgfont 95 | 96 | 2 97 | 98 | name 99 | constant.numeric.ivgfont 100 | 101 | 102 | contentName 103 | string.other.ivgfont 104 | patterns 105 | 106 | 107 | include 108 | source.impd#stringEscape 109 | 110 | 111 | 112 | 113 | repository 114 | 115 | 116 | 117 | -------------------------------------------------------------------------------- /tmLanguages/soniccharge/makaron.tmLanguage: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | $schema 6 | https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json 7 | name 8 | makaron 9 | scopeName 10 | source.makaron 11 | fileTypes 12 | 13 | makaron 14 | 15 | foldingStartMarker 16 | (@begin|@<|@if) 17 | foldingStopMarker 18 | (@end|@>|@endif) 19 | patterns 20 | 21 | 22 | include 23 | #root 24 | 25 | 26 | repository 27 | 28 | root 29 | 30 | patterns 31 | 32 | 33 | include 34 | #literalAt 35 | 36 | 37 | include 38 | #macroDefinition 39 | 40 | 41 | include 42 | #valueDefinition 43 | 44 | 45 | include 46 | #ifStatement 47 | 48 | 49 | include 50 | #includeFile 51 | 52 | 53 | include 54 | #invokeMacro 55 | 56 | 57 | 58 | literalAt 59 | 60 | patterns 61 | 62 | 63 | name 64 | constant.character.escape.makaron 65 | match 66 | @@ 67 | 68 | 69 | 70 | macroDefinition 71 | 72 | name 73 | meta.function.makaron 74 | begin 75 | (@begin)\b\s+([a-zA-Z$_][a-zA-Z0-9$_]*) 76 | end 77 | (@end)\b 78 | beginCaptures 79 | 80 | 1 81 | 82 | name 83 | storage.type.function.makaron 84 | 85 | 2 86 | 87 | name 88 | entity.name.function.makaron 89 | 90 | 91 | endCaptures 92 | 93 | 1 94 | 95 | name 96 | storage.type.function.makaron 97 | 98 | 99 | patterns 100 | 101 | 102 | include 103 | #macroName 104 | 105 | 106 | include 107 | #root 108 | 109 | 110 | 111 | macroName 112 | 113 | begin 114 | (?<=[a-zA-Z0-9$_])\( 115 | end 116 | \) 117 | captures 118 | 119 | 0 120 | 121 | name 122 | entity.name.function.makaron 123 | 124 | 125 | patterns 126 | 127 | 128 | include 129 | #paramsList 130 | 131 | 132 | include 133 | #root 134 | 135 | 136 | 137 | paramsList 138 | 139 | patterns 140 | 141 | 142 | name 143 | variable.parameter.makaron 144 | match 145 | [a-zA-Z$_][a-zA-Z0-9$_]* 146 | 147 | 148 | 149 | raw 150 | 151 | begin 152 | @< 153 | end 154 | @> 155 | captures 156 | 157 | 0 158 | 159 | name 160 | constant.character.escape.makaron 161 | 162 | 163 | contentName 164 | meta.raw.cushy 165 | patterns 166 | 167 | 168 | include 169 | #literalAt 170 | 171 | 172 | include 173 | #raw 174 | 175 | 176 | include 177 | #root 178 | 179 | 180 | 181 | balanced 182 | 183 | patterns 184 | 185 | 186 | name 187 | meta.structure.balanced.paranthesis.makaron 188 | begin 189 | \( 190 | end 191 | \) 192 | patterns 193 | 194 | 195 | include 196 | #root 197 | 198 | 199 | 200 | 201 | name 202 | meta.structure.balanced.braces.makaron 203 | begin 204 | { 205 | end 206 | } 207 | patterns 208 | 209 | 210 | include 211 | #root 212 | 213 | 214 | 215 | 216 | name 217 | meta.structure.balanced.brackets.makaron 218 | begin 219 | \[ 220 | end 221 | \] 222 | patterns 223 | 224 | 225 | include 226 | #root 227 | 228 | 229 | 230 | 231 | 232 | name 233 | string.quoted.double.makaron 234 | begin 235 | " 236 | end 237 | " 238 | patterns 239 | 240 | 241 | include 242 | #stringEscape 243 | 244 | 245 | 246 | 247 | name 248 | string.quoted.single.makaron 249 | begin 250 | ' 251 | end 252 | ' 253 | patterns 254 | 255 | 256 | include 257 | #stringEscape 258 | 259 | 260 | 261 | 262 | 263 | 264 | valueDefinition 265 | 266 | name 267 | meta.define.makaron 268 | begin 269 | (@(?:re)?define)\b\s+([a-zA-Z$_][a-zA-Z0-9$_]*)(\s*\=) 270 | end 271 | (?=[\n]) 272 | beginCaptures 273 | 274 | 1 275 | 276 | name 277 | storage.type.macro.makaron 278 | 279 | 2 280 | 281 | name 282 | entity.name.macro.makaron 283 | 284 | 3 285 | 286 | name 287 | keyword.operator.assignment.makaron 288 | 289 | 290 | endCaptures 291 | 292 | 0 293 | 294 | name 295 | keyword.terminator.statement.makaron 296 | 297 | 298 | patterns 299 | 300 | 301 | include 302 | #expression 303 | 304 | 305 | include 306 | #root 307 | 308 | 309 | 310 | ifStatement 311 | 312 | name 313 | meta.block.conditional.makaron 314 | begin 315 | @if 316 | end 317 | @endif 318 | captures 319 | 320 | 0 321 | 322 | name 323 | keyword.control.conditional.makaron 324 | 325 | 326 | patterns 327 | 328 | 329 | include 330 | #condition 331 | 332 | 333 | include 334 | #ifStatement 335 | 336 | 337 | name 338 | keyword.control.conditional.makaron 339 | match 340 | (@elif|@else) 341 | 342 | 343 | include 344 | #root 345 | 346 | 347 | 348 | expression 349 | 350 | name 351 | meta.expression.makaron 352 | patterns 353 | 354 | 355 | include 356 | #literalAt 357 | 358 | 359 | include 360 | #raw 361 | 362 | 363 | include 364 | #balanced 365 | 366 | 367 | include 368 | #invokeMacro 369 | 370 | 371 | 372 | condition 373 | 374 | name 375 | meta.block.condition.makaron 376 | begin 377 | \( 378 | end 379 | \) 380 | captures 381 | 382 | 0 383 | 384 | name 385 | keyword.control.conditional.makaron 386 | 387 | 388 | patterns 389 | 390 | 391 | include 392 | #expression 393 | 394 | 395 | name 396 | keyword.operator.compare.makaron 397 | match 398 | (==|!=) 399 | 400 | 401 | 402 | invokeMacro 403 | 404 | patterns 405 | 406 | 407 | name 408 | meta.macro.invoke.makaron 409 | begin 410 | @[a-zA-Z$_][a-zA-Z0-9$_]*\( 411 | end 412 | \) 413 | captures 414 | 415 | 0 416 | 417 | name 418 | entity.name.function.makaron 419 | 420 | 421 | patterns 422 | 423 | 424 | include 425 | #expression 426 | 427 | 428 | 429 | 430 | name 431 | entity.name.macro.makaron 432 | match 433 | @[a-zA-Z$_][a-zA-Z0-9$_]*\b 434 | 435 | 436 | name 437 | meta.macro.indirect.makaron 438 | begin 439 | @\( 440 | end 441 | \) 442 | captures 443 | 444 | 0 445 | 446 | name 447 | variable.other.makaron 448 | 449 | 450 | contentName 451 | variable.other.makaron 452 | patterns 453 | 454 | 455 | include 456 | #expression 457 | 458 | 459 | 460 | 461 | 462 | includeFile 463 | 464 | name 465 | meta.include.makaron 466 | begin 467 | (@include\b)\s+ 468 | end 469 | (?=[\n]) 470 | beginCaptures 471 | 472 | 1 473 | 474 | name 475 | keyword.control.include.makaron 476 | 477 | 478 | endCaptures 479 | 480 | 0 481 | 482 | name 483 | keyword.terminator.statement.makaron 484 | 485 | 486 | patterns 487 | 488 | 489 | include 490 | #expression 491 | 492 | 493 | 494 | stringEscape 495 | 496 | patterns 497 | 498 | 499 | include 500 | #makaron 501 | 502 | 503 | match 504 | \\. 505 | name 506 | constant.character.escape 507 | 508 | 509 | 510 | 511 | 512 | 513 | -------------------------------------------------------------------------------- /tmLanguages/soniccharge/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "soniccharge", 3 | "displayName": "Sonic Charge", 4 | "description": "Syntax highlighting for Sonic Charge file formats", 5 | "version": "1.0.0", 6 | "publisher": "Sonic Charge", 7 | "engines": { 8 | "vscode": "^1.74.0" 9 | }, 10 | "categories": [ 11 | "Programming Languages" 12 | ], 13 | "contributes": { 14 | "languages": [{ 15 | "id": "cushyschema", 16 | "aliases": ["cushyschema", "cushyschema"], 17 | "extensions": [".schema"], 18 | "configuration": "./soniccharge.language-configuration.json" 19 | },{ 20 | "id": "cushy", 21 | "aliases": ["cushy", "cushy"], 22 | "extensions": [".cushy"], 23 | "configuration": "./soniccharge.language-configuration.json" 24 | },{ 25 | "id": "makaron", 26 | "aliases": ["makaron", "makaron"], 27 | "extensions": [".makaron"], 28 | "configuration": "./soniccharge.language-configuration.json" 29 | },{ 30 | "id": "ivg", 31 | "aliases": ["ivg", "ivg"], 32 | "extensions": [".ivg"], 33 | "configuration": "./soniccharge.language-configuration.json" 34 | },{ 35 | "id": "ivgfont", 36 | "aliases": ["ivgfont", "ivgfont"], 37 | "extensions": [".ivgfont"], 38 | "configuration": "./soniccharge.language-configuration.json" 39 | },{ 40 | "id": "impd", 41 | "aliases": ["impd", "impd"], 42 | "extensions": [".impd"], 43 | "configuration": "./soniccharge.language-configuration.json" 44 | }], 45 | "grammars": [{ 46 | "language": "cushyschema", 47 | "scopeName": "source.cushyschema", 48 | "path": "./cushyschema.tmLanguage" 49 | },{ 50 | "language": "cushy", 51 | "scopeName": "source.cushy", 52 | "path": "./cushy.tmLanguage" 53 | },{ 54 | "language": "makaron", 55 | "scopeName": "source.makaron", 56 | "path": "./makaron.tmLanguage" 57 | },{ 58 | "language": "ivg", 59 | "scopeName": "source.ivg", 60 | "path": "./ivg.tmLanguage" 61 | },{ 62 | "language": "ivgfont", 63 | "scopeName": "source.ivgfont", 64 | "path": "./ivgfont.tmLanguage" 65 | },{ 66 | "language": "impd", 67 | "scopeName": "source.impd", 68 | "path": "./impd.tmLanguage" 69 | }] 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /tmLanguages/soniccharge/soniccharge.language-configuration.json: -------------------------------------------------------------------------------- 1 | { 2 | "comments": { 3 | // symbol used for single line comment. Remove this entry if your language does not support line comments 4 | "lineComment": "//", 5 | // symbols used for start and end a block comment. Remove this entry if your language does not support block comments 6 | "blockComment": [ "/*", "*/" ] 7 | }, 8 | // symbols used as brackets 9 | "brackets": [ 10 | ["{", "}"], 11 | ["[", "]"], 12 | ["(", ")"] 13 | ], 14 | // symbols that are auto closed when typing 15 | "autoClosingPairs": [ 16 | ["{", "}"], 17 | ["[", "]"], 18 | ["(", ")"], 19 | ["\"", "\""], 20 | ["'", "'"] 21 | ], 22 | // symbols that can be used to surround a selection 23 | "surroundingPairs": [ 24 | ["{", "}"], 25 | ["[", "]"], 26 | ["(", ")"], 27 | ["\"", "\""], 28 | ["'", "'"] 29 | ] 30 | } --------------------------------------------------------------------------------