dreemgl
Version:
DreemGL is an open-source multi-screen prototyping framework for mediated environments, with a visual editor and shader styling for webGL and DALi runtimes written in JavaScript. As a toolkit for gpu-accelerated multiscreen development, DreemGL includes
564 lines (449 loc) • 16.9 kB
JavaScript
/* DreemGL is a collaboration between Teeming Society & Samsung Electronics, sponsored by Samsung and others.
Copyright 2015-2016 Teeming Society. Licensed under the Apache License, Version 2.0 (the "License"); You may not use this file except in compliance with the License.
You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.*/
define.class(function(require, exports){
this.space = ' '
this.newline = '\n'
this.indent = '\t'
this.line = 0
this.comma = ',' + this.space
this.term = ';'
this.expand = function(node, parent, state){ // recursive expansion
if(!state) throw new Error('Please pass in state {depth:""}')
if(!node || !node.type) return ''
node.parent = parent
node.infer = undefined
if(!this[node.type]) throw new Error('Undefined type in OneJSGen:' + node.type)
var ret = this[node.type](node, parent, state)
// lets pass the inference up
if(node.infer && parent && !parent.infer) parent.infer = node.infer
if(node.store){
if(node.store & 1) ret = ret + '..'
if(node.store & 2) ret = ret + '!'
if(node.store & 4) ret = ret + '~'
}
if(state.trace){
var out = state.depth + node.type + ''
if(node.type === "Call") out += " fn:" +node.fn.name
if(node.type == "Id") out += ' name:' + node.name
if(node.type == "Value") out += ' value:' + node.value
console.log(out)
}
return ret
}
this.block = function(array, parent, state, noindent){ // term split array
state = Object.create(state)
if(!noindent) state.depth += this.indent
var ret = ''
for(var i = 0; i < array.length; i++){
var node = array[ i ]
var blk = this.expand(node, parent, state)
if(blk === undefined) throw new Error('ast node ' + node.type + ' returned undefined in block')
if(blk[0] == '(' || blk[0] == '[') ret += state.depth + ';' + blk
else ret += state.depth + blk
if(this.term) ret += this.term
if(ret[ret.length - 1] !== '\n' ) ret += this.newline, this.line++
}
return ret
}
this.flat = function(array, parent, state){
var ret = ''
for(var i = 0; i < array.length; i++){
if(i) ret += this.comma
ret += this.expand(array[i], parent, state)
}
return ret
}
this.list = function(array, parent, state){
var ret = ''
for(var i = 0; i < array.length; i++){
if(ret !== '') ret += this.comma
ret += this.expand(array[i], parent, state)
if(ret[ret.length - 1] == '\n'){
ret += state.depth
if(i !== len - 1) ret += this.indent
}
}
return ret
}
this.needsParens = function(node, other, isleft){
var other_t = other.type
if(other_t == 'Assign' || other_t == 'List' || other_t == 'Condition' ||
(other_t == 'Binary' || other_t == 'Logic') && other.prio <= node.prio){
if(other.prio == node.prio && isleft) return false
return true
}
}
this.Program = function(node, parent, state){
return this.block(node.steps, node, state, true)
}
this.Empty = function(node, parent, state){
return ''
}
this.Id = function(node, parent, state){
var flag = node.flag
if(flag){
if(flag === -1) return '..'
if(flag === 46) return '.' + node.name
if(flag === 126) return node.name + '~'
if(flag === 33) return node.name + '!'
if(flag === 64) return '@' + (node.name!==undefined?node.name:'')
if(flag === 35) return '#' + (node.name!==undefined?node.name:'')
}
if(node.typing) return this.expand(node.typing, node, state) + ' ' + node.name
return node.name
}
this.Define = function(node, parent, state){ throw new Error('depricated') }
this.Value = function(node, parent, state){
return node.raw
}
// string, number, bool
this.This = function(node, parent, state){
return 'this'
}
this.Array = function(node, parent, state){
var ret = '[' +
this.list(node.elems, node, state) +
']'
return ret
}
this.Object = function(node, parent, state){
var nstate = Object.create(state)
nstate.depth += this.indent
var keys = node.keys
var len = keys.length
var ret = '{' + this.space
for(var i = 0; i < len; i++){
var prop = keys[i]
if(i) ret += ',' + this.space
var ch = ret[ret.length -1]
if(ch == '\n') ret += nstate.depth
else if(ch == '}') ret += this.newline + nstate.depth
ret += prop.key.name || prop.key.raw
if(prop.short === undefined){
ret += ':' + this.expand(prop.value, node, nstate)
}
}
var ch = ret[ ret.length - 1 ]
if( ch == '\n') ret += state.depth +'}'
else{
if( ch == '}' ) ret += this.newline + state.depth + '}'
else ret += this.space + '}'
}
return ret
}
this.Index = function(node, parent, state){
var obj = node.object
var object_t = obj.type
var object = this.expand(obj, node, state)
if(object_t !== 'Index' && object_t !== 'Id' && object_t !== 'Key' && object_t !== 'Call' && object_t !== 'This' && object_t !== 'ThisCall')
object = '(' + object + ')'
return object + '[' + this.expand(node.index, node, state) + ']'
}
this.Key = function(node, parent, state){
var obj = node.object
var object_t = obj.type
var object = this.expand(obj, node, state)
if(object_t !== 'Index' && object_t !== 'Id' && object_t !== 'Key' && object_t !== 'Call'&& object_t !== 'This' && object_t !== 'ThisCall')
object = '(' + object + ')'
return object + (this.exist?'?.':'.') + this.expand(node.key, node, state)
}
this.ThisCall = function(node, parent, state){
var obj = node.object
var object_t = obj.type
var object = this.expand(obj, node)
if(object_t !== 'Index' && object_t !== 'Id' && object_t !== 'Key' && object_t !== 'Call'&& object_t !== 'This' && object_t !== 'ThisCall')
object = '(' + object + ')'
return object + '::' + this.expand(node.key, node)
}
this.Block = function(node, parent, state){
var ret = '{' + this.newline + this.block(node.steps, node, state) + state.depth + '}'
return ret
}
this.List = function(node, parent, state){
return this.list(node.items, node, state)
}
this.Comprehension = function(node, parent, state){
return '1'
}
this.Template = function(node, parent, state){
var ret = '`'
var chain = node.chain
var len = chain.length
for(var i = 0; i < len; i++){
var item = chain[i]
if(item.type == 'Block'){
if(item.steps.length == 1 && outer.IsExpr[item.steps[0].type]){
ret += '{' + this.expand(item.steps[0], node, state) + '}'
}
else ret += this.expand(item, node, state)
}
else {
if(item.value !== undefined) ret += item.value
}
}
ret += '`'
return ret
}
this.Break = function(node, parent, state){
return 'break' + (node.label? ' ' + this.expand(node.label, node, state): '')
}
this.Continue = function(node, parent, state){
return 'continue'+(node.label?' '+this.expand(node.label, node, state): '')
}
this.Label = function(node, parent, state){
return this.expand(node.label, node, state) + ':' + this.expand(node.body, node, state)
}
this.If = function(node, parent, state){
var ret = 'if('
ret += this.expand(node.test, node, state)
if(ret[ret.length - 1] == '\n') ret += state.depth + this.indent
ret += ')' + this.space + this.expand(node.then, node, state)
if(node.else){
var ch = ret[ret.length - 1]
if( ch !== '}' && this.term) ret += this.term
if( ch !== '\n' ) ret += this.newline
ret += state.depth + 'else ' + this.expand(node.else, node, state)
}
return ret
}
this.Switch = function(node, parent, state){
var ret = 'switch(' + this.expand(node.on, node, state) + '){'
ret += this.newline
var nstate = Object.create(state)
nstate.depth += this.indent
var cases = node.cases
if(cases) for( var i = 0; i < cases.length; i++ ) ret += nstate.depth + this.expand(cases[i], node, nstate)
ret += state.depth + '}'
return ret
}
this.Case = function(node, parent, state){
if(!node.test){
return 'default:' + (node.steps.length? this.newline+this.block(node.steps, node, state): this.newline)
}
var ret = 'case '
ret += this.expand(node.test, node) + ':'
ret += this.newline
if(node.steps.length) ret += this.block(node.steps, node)
return ret
}
this.Throw = function(node, parent, state){
return 'throw ' + this.expand(node.arg, node)
}
this.Try = function(node, parent, state){
var ret = 'try' + this.expand(node.try, node)
if(node.catch){
if(node.arg.type !== 'Id') throw new Error("unsupported catch type")
var name = node.arg.name
ret += 'catch(' + name + ')' + this.expand(node.catch, node, state)
}
if(node.finally) ret += 'finally' + this.expand(node.finally, node, state)
return ret
}
this.While = function(node, parent, state){
return 'while(' + this.expand(node.test, node, state) + ')' +
this.expand(node.loop, node, state)
}
this.DoWhile = function(node, parent, state){
return 'do' + this.expand(node.loop, node, state) +
'while(' + this.expand(node.test, node, state) + ')'
}
this.For = function(node, parent, state){
return 'for(' + this.expand(node.init, node, state)+';'+
this.expand(node.test, node, state) + ';' +
this.expand(node.update, node, state) + ')' +
this.expand(node.loop, node, state)
}
this.ForIn = function(node, parent, state){
return 'for(' + this.expand(node.left, node, state) + ' in ' +
this.expand(node.right, node, state) + ')' +
this.expand(node.loop, node, state)
}
this.ForOf = function(node, parent, state){
return 'for(' + this.expand(node.left, node, state) + ' of ' +
this.expand(node.right, node, state) + ')' +
this.expand(node.loop, node, state)
}
this.ForFrom = function(node, parent, state){
return 'for(' + this.expand(node.left, node, state) + ' from ' +
this.expand(node.right, node, state) + ')' +
this.expand(node.loop, node, state)
}
this.ForTo = function(node, parent, state){
return 'for(' + this.expand(node.left, node, state) + ' to ' +
this.expand(node.right, node, state) +
(node.in?' in ' + this.expand(node.in, node, state):'') + ')' +
this.expand(node.loop, node, state)
}
this.Var = function(node, parent, state){
return 'var ' + this.flat(node.defs, node, state)
}
this.TypeVar = function(node, parent, state){
return this.expand(node.typing, node, state) + ' ' +
this.flat(node.defs, node, state)
}
this.Def = function(node, parent, state){
return this.expand(node.id, node, state) +
(node.init ? this.space + '=' + this.space + this.expand(node.init, node, state) : '')
}
this.Struct = function(node, parent, state){
return 'struct ' + this.expand(node.id, node, state) + this.expand(node.struct, node, state)
}
this.Enum = function(node, parent, state){
return 'enum ' + this.expand(node.id, node) + '{' + this.newline +
state.depth + this.indent + this.list(node.enums, node, state) +'}'
}
this.Function = function(node, parent, state){
if(node.arrow){
var arrow = node.arrow
// if an arrow has just one Id as arg leave off ( )
if( !node.name && !node.rest && node.params && node.params.length == 1 && !node.params[0].init && node.params[0].id.type == 'Id' ){
return this.expand(node.params[0].id, node, state) + arrow + this.expand(node.body, node, state)
}
var ret = ''
if(node.name) ret += this.expand(node.name, node, state)
ret += '(' +(node.params?this.list(node.params, node, state):'') +
(node.rest ? ',' + this.space + this.expand(node.rest, node, state) : '' )+ ')'
if(!node.name || node.body.type != 'Block' || arrow != '->') ret += arrow
ret += this.expand(node.body, node)
this.cignore = 1
return ret
}
var ret
if(node.name) ret = this.expand(node.name)
else ret = 'function'
if( node.gen ) ret += '*'
if( node.id ) ret += ' '+this.expand(node.id, node, state)
ret += '('+this.list(node.params, node, state)
if( node.rest ) ret += ',' + this.expand(node.rest, node, state)
ret += ')'
ret += this.expand(node.body, node, state)
return ret
}
this.Return = function(node, parent, state){
if(!node.arg) return 'return'
return 'return ' + this.expand(node.arg, node, state)
}
this.Yield = function(node, parent, state){
if(!node.arg) return 'yield'
return 'yield ' + this.expand(node.arg, node, state)
}
this.Await = function(node, parent, state){
if(!node.arg) return 'await'
return 'await ' + this.expand(node.arg, node, state)
}
this.Unary = function(node, parent, state){
var arg = this.expand(node.arg, node, state)
var atype = node.arg.type
if(node.prefix){
if(atype == 'Assign' || atype == 'Binary' ||
atype == 'Logic' || atype == 'Condition')
arg = '(' + arg + ')'
if(node.op.length != 1) return node.op + ' ' + arg
return node.op + arg
}
return arg + node.op
}
// alright so how are we going to do parens?
this.Binary = function(node, parent, state){
var left = this.expand(node.left, node, state)
var right = this.expand(node.right, node, state)
if(this.needsParens(node, node.left)) left = '(' + left + ')'
if(this.needsParens(node, node.right)) right = '(' + right + ')'
return left + this.space + node.op + this.space + right
}
this.Logic = function(node, parent, state){
var left = this.expand(node.left, node, state)
var right = this.expand(node.right, node, state)
if(this.needsParens(node, node.left)) left = '(' + left + ')'
if(this.needsParens(node, node.right)) right = '(' + right + ')'
return left + this.space + node.op + this.space + right
}
this.Assign = function(node, parent, state){
var left = this.expand(node.left, node, state)
var right = this.expand(node.right, node, state)
return left + this.space + node.op + this.space + right
}
this.Update = function(node, parent, state){
if(node.prefix) return node.op + this.expand(node.arg, node, state)
return this.expand(node.arg, node, state) + node.op
}
this.Condition = function(node, parent, state){
// if we have a test of logic or binary
var test = this.expand(node.test, node, state)
var test_t = node.test.type
if(test_t == 'Assign' || test_t == 'List' ||
test_t == 'Logic' || test_t == 'Binary') test = '(' + test + ')'
var else_v = this.expand(node.else, node, state)
var else_t = node.else.type
if(else_t == 'Assign' || else_t == 'List' ||
else_t == 'Logic' || else_t == 'Binary') else_v = '(' + else_v + ')'
return test + '?' +
this.space + this.expand(node.then, node, state) + ':' +
this.space + else_v
}
this.New = function(node, parent, state){
var fn = this.expand(node.fn, node, state)
var fn_t = node.fn.type
if(fn_t == 'List' || fn_t == 'Logic' || fn_t == 'Condition')
fn = '(' + fn + ')'
return 'new ' + fn + '(' + this.list(node.args, node, state) + ')'
}
this.callArgs = function(node, parent, state){
var arg = ''
if(node.first_args) arg += this.list(node.first_args, node, state)
if(node.args && node.args.length){
if(arg) arg += ', '
arg += this.list(node.args, node, state)
}
if(node.last_args){
if(arg) arg += ', '
arg += this.list(node.last_args, node, state)
}
return arg
}
this.Call = function(node, parent, state){
var fn = this.expand(node.fn, node, state)
var fn_t = node.fn.type
if(fn_t == 'Function' || fn_t == 'List' || fn_t == 'Logic' || fn_t == 'Condition')
fn = '(' + fn + ')'
return fn + '(' + this.callArgs(node, parent, state) + ')'
}
this.Nest = function(node, parent, state){
return this.expand(node.fn, node, state) + this.expand(node.body, node, state)
}
this.Class = function(node, parent, state){
var ret = 'class ' + node.id.name
if(node.base) ret += ' extends ' + node.base.name
ret += this.expand(node.body, node, state)
return ret
}
this.Quote = function(node, parent, state){
var ret = ':' + this.expand(node.quote, node, state)
return ret
}
this.Signal = function(node, parent, state){
var left = this.expand(node.left, node, state)
var right = this.expand(node.right, node, state)
return left + ':=' + this.space + quote
}
this.AssignQuote = function(node, parent, state){
var left = this.expand(node.left, node, state)
var quote = this.expand(node.quote, node, state)
return left + ':' + this.space + quote
}
this.Rest = function(node, parent, state){
return '...' + this.expand(node.id, node, state)
}
this.CallBlock = function(node, parent, state){
return this.expand(node.object, node, state) + this.expand(node.body, node, state)
}
this.Debugger = function(node, parent, state){
return 'debugger'
}
this.With = function(node, parent, state){
return 'with(' + this.expand(node.object, node, state) + ')' + this.expand(node.body, node, state)
}
})