Pygmentx

This is an online syntax highlighter using Pygments. Mainly used for testing the improved Haxe lexer which is located at my fork over here. Let me know (@andy_li) if you find some valid Haxe code is highlighted wrong (not about the color scheme).

/*
* HxSL - Haxe Shader Language
*
* Copyright (c) 2012, The haXe Project Contributors
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE HAXE PROJECT CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE HAXE PROJECT CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*/
package hxsl;
import hxsl.Data;
private typedef VarProps = {
var global : Bool;
var read : Bool;
var write : Int;
var newVar : Variable;
var isVertex : Bool;
var value : Const;
var ref : Variable;
}
/**
The RuntimeCompiler is in charge of :
- eliminating conditional constructs (If/Cond)
- evaluating Row/Vector
- inlining the For loops
- allocating variables index
- creating constant pool
- adding extra padding to ensure platform compat
**/
class RuntimeCompiler {
var varProps : Map<Int,VarProps>;
var usedVars : Array<Variable>;
var constVars : Array<Variable>;
var objectVars : Map<Int,{ v : Variable, fields : Map<String,Variable> }>;
var varId : Int;
// force replace of variables by their provided value
var isCond : Bool;
// do not force constants to be replaced by variables
var isConst : Bool;
var cur : Code;
var defPos : Position;
public static var DEFAULT_CONFIG = {
padWrites : true,
};
public var config : { padWrites : Bool };
public function new() {
varId = 0;
config = DEFAULT_CONFIG;
}
function error( msg : String, pos : Position ) : Dynamic {
if( pos == null ) pos = defPos;
throw new Error(msg, pos);
return null;
}
function props( v : Variable ) {
var p = varProps.get(v.id);
if( p == null ) {
p = {
global : false,
read : false,
write : 0,
newVar : null,
value : CNull,
isVertex : false,
ref : null,
}
varProps.set(v.id,p);
}
return p;
}
/**
Compile the final shader : the params is a mapping of all the variables that will be applied at compilation time.
The can be of the following value :
* null
* true/false for Bool
* an Int base index in the paramsData table for all other types
**/
public function compile( data : Data, ?params : { }, ?paramsData : haxe.ds.Vector<Float> ) : Data {
usedVars = [];
constVars = [];
varProps = new Map();
objectVars = new Map();
defPos = data.vertex.pos;
var hVars = new Map();
for( v in data.globals.concat(data.vertex.args).concat(data.fragment.args) )
switch( v.kind ) {
case VConst, VParam:
hVars.set(v.name, v);
case VInput:
props(v).global = true;
default:
}
if( params != null )
for( f in Reflect.fields(params) ) {
var v = hVars.get(f);
if( v == null )
error("Unknown params " + f, null);
var val : Dynamic = Reflect.field(params, f);
if( val == null )
continue;
function makeVal(val:Dynamic, t:VarType) {
if( val == null )
return CNull;
switch( t ) {
case TNull, TTexture(_): throw "assert";
case TBool:
if( !Std.is(val, Bool) )
error("Invalid value for parameter " + v.name, null);
return CBool(val);
case TFloat:
if( !Std.is(val, Float) )
error("Invalid value for parameter " + v.name, null);
return CFloat(val);
case TArray(t, 0):
if( !Std.is(val, Array) )
error("Invalid value for parameter " + v.name, null);
var a : Array<Dynamic> = val;
return CArray([for( v in a ) makeVal(v, t)]);
case TInt, TFloat2, TFloat3, TFloat4, TMatrix(_), TArray(_):
if( !Std.is(val, Int) )
error("Invalid value for parameter " + v.name, null);
var index : Int = val;
var size = Tools.floatSize(v.type);
var a = [];
for( i in 0...size ) {
var v = paramsData == null ? 0 : paramsData[i + index];
#if !flash if( v == null ) v = 0; #end
a.push(v);
}
return a.length == 1 ? CFloat(a[0]) : CFloats(a);
case TObject(fields):
if( !Reflect.isObject(val) )
error("Invalid value for parameter " + v.name, null);
var obj = new Map();
for( f in fields ) {
var fv = Reflect.field(val, f.name);
if( fv != null )
obj.set(f.name, makeVal(fv, f.t));
}
return CObject(obj);
}
}
props(v).value = makeVal(val, v.type);
}
var vertex = compileCode(data.vertex);
var vconst = constVars;
constVars = [];
var fragment = compileCode(data.fragment);
var fconst = constVars;
constVars = [];
usedVars.sort(sortById);
indexVars(vertex, vconst);
indexVars(fragment, fconst);
var globals = [];
for( v in usedVars ) {
if( !props(v).global )
continue;
globals.push(v);
}
return {
globals : globals,
vertex : vertex,
fragment : fragment,
};
}
function isUnsupportedWriteMask( s : Array<Comp> ) {
return s != null && s.length > 1 && (s[0] != X || s[1] != Y || (s.length > 2 && (s[2] != Z || (s.length > 3 && s[3] != W))));
}
function indexVars( c : Code, constVars : Array<Variable> ) {
var indexes = [0, 0, 0, 0, 0, 0];
function calculateUsedSize( v : Variable, index : { i : Int } ) : { v : Variable, size : Int } {
v.index = index.i;
var p = props(v);
if( p.ref != null ) p.ref.index = v.index;
switch( v.type ) {
case TObject(fields):
var o = objectVars.get(v.id);
if( o == null ) throw "assert"; // not really used it seems ?
// only take into account the actual used registers
var tot = 0;
var fl = [];
for( f in fields ) {
var fv = o.fields.get(f.name);
if( fv != null ) {
var k = calculateUsedSize(fv, index);
tot += k.size;
fl.push({ name : f.name, t : k.v.type });
}
}
// mute the variable in usedVars with the one with the actual fields
var index = Lambda.indexOf(usedVars, v);
if( index >= 0 ) {
v = { id : v.id, index : v.index, kind : v.kind, name : v.name, pos : v.pos, type : TObject(fl) };
usedVars[index] = v;
}
return { v : v, size : tot };
case TArray(_, size) if( objectVars.exists(v.id) ):
var o = objectVars.get(v.id);
var tot = 0;
for( i in 0...size ) {
var fv = o.fields.get(""+i);
var k = calculateUsedSize(fv, index);
tot += k.size;
}
return { v : v, size : tot };
default:
var size = Tools.regSize(v.type);
index.i += size;
return { v : v, size : size };
}
}
for( v in usedVars.copy() ) {
var p = props(v);
if( p.isVertex == c.vertex ) {
var tkind = Type.enumIndex(v.kind);
var inf = calculateUsedSize(v, { i : indexes[tkind] } );
var v = inf.v;
indexes[tkind] += inf.size;
switch( v.kind ) {
case VConst, VTexture:
c.args.push(v);
props(v).global = false; // remove from global list
case VParam:
throw "assert"; // should have been translated to VConst
case VInput, VOut, VVar, VTmp:
}
}
}
// move consts at the end
var cdelta = indexes[Type.enumIndex(VConst)];
for( v in constVars ) {
if( v.kind != VConst ) throw "assert";
v.index += cdelta;
}
c.tempSize = indexes[Type.enumIndex(VTmp)];
}
function sortById( v1 : Variable, v2 : Variable ) {
return v1.id - v2.id;
}
function compileCode( c : Code ) : Code {
isCond = false;
isConst = false;
cur = {
vertex : c.vertex,
args : [],
consts : [],
exprs : [],
pos : c.pos,
tempSize : 0,
};
for( e in c.exprs )
compileAssign(e.v, e.e);
checkVars();
return cur;
}
function checkVars() {
for( v in usedVars ) {
var p = props(v);
switch( v.kind ) {
case VVar:
if( p.write != fullBits(v.type) )
error("Some components of variable '" + v.name + "' are not written by vertex shader", v.pos);
else if( p.write != 15 && cur.vertex ) {
// force the output write
padWrite(v);
}
default:
}
}
}
function isGoodSwiz( s : Array<Comp> ) {
if( s == null ) return true;
var cur = 0;
for( x in s )
if( Type.enumIndex(x) != cur++ )
return false;
return true;
}
function padWrite( v : Variable ) {
if( !config.padWrites )
return;
// if we already have a partial "mov" copy, we can simply extend the writing on other components
for( e in cur.exprs ) {
if( e.v == null ) continue;
switch( e.v.d ) {
case CVar(vv, sv):
if( v == vv && isGoodSwiz(sv) ) {
switch( e.e.d ) {
case CVar(v2, sv2):
// only allow "mov" extension if we are sure that the variable is padded with "1"
if( v2.kind == VInput || v2.kind == VVar ) {
// remove swizzle on write
var vn = Reflect.copy(v);
props(v).ref = vn;
vn.type = TFloat4;
e.v.d = CVar(vn);
// remove swizzle on read
if( isGoodSwiz(sv2) ) {
var p = props(v2);
var vn2 = p.ref;
// allow several writes
if( vn2 == null ) {
vn2 = Reflect.copy(v2);
vn2.type = TFloat4;
p.ref = vn2;
}
e.e.d = CVar(vn2);
} else
// or pad swizzle on input var
while( sv2.length < 4 )
sv2.push(X);
// adjust types
e.e.t = e.v.t = TFloat4;
return;
}
default:
}
}
default:
}
}
// store 1-values into remaining components
var missing = [], ones = [];
for( i in Tools.floatSize(v.type)...4 ) {
missing.push(Type.createEnumIndex(Comp, i));
ones.push(1.);
}
var c = allocConst(ones, v.pos);
addAssign({ d : CVar(v, missing), t : Tools.makeFloat(missing.length), p : v.pos },c, v.pos);
}
function addAssign( v, e, p ) {
cur.exprs.push( { v : v, e : e } );
}
function allocVar(name, k, t, p) {
var id = -(varId + 1);
varId++;
var v : Variable = {
id : id,
name : name,
kind : k,
type : t,
index : -1,
pos : p,
};
return v;
}
function makeConst(index:Int, swiz, p) {
var v = allocVar("$c" + index, VConst, TFloat4, p);
constVars.push(v);
v.index = index;
return { d : CVar(v, swiz), t : Tools.makeFloat(swiz.length), p : p };
}
function mergeSwiz(from:Array<Comp>, to:Array<Comp>) {
var out = [];
for( s in to )
out.push( from[Type.enumIndex(s)] );
return out;
}
function allocConst( cvals : Array<Float>, p : Position ) : CodeValue {
var swiz = [X, Y, Z, W];
var dup = [];
var dvals = [];
// de-dupe the input values
for( i in 0...cvals.length ) {
var found = false;
for( j in 0...dvals.length ) {
if ( cvals[i] == dvals[j] ) {
dup.push(swiz[j]);
found = true;
break;
}
}
if( !found ) {
dup.push(swiz[dvals.length]);
dvals.push(cvals[i]);
}
}
// find an already existing constant
for( index in 0...cur.consts.length ) {
var c = cur.consts[index];
var s = [];
for( v in dvals ) {
for( i in 0...c.length )
if( c[i] == v ) {
s.push(swiz[i]);
break;
}
}
if( s.length == dvals.length )
return makeConst(index,mergeSwiz(s,dup),p);
}
// find an empty slot
for( i in 0...cur.consts.length ) {
var c = cur.consts[i];
if( c.length + dvals.length <= 4 ) {
var s = [];
for( v in dvals ) {
s.push(swiz[c.length]);
c.push(v);
}
return makeConst(i,mergeSwiz(s,dup),p);
}
}
var index = cur.consts.length;
cur.consts.push(dvals);
return makeConst(index, mergeSwiz(swiz.splice(0, dvals.length),dup), p);
}
function isTrue( c : Const ) {
return switch( c ) {
case CNull: false;
case CInt(i): i != 0;
case CFloat(f): f != 0;
case CBool(b): b;
case CFloats(_), CObject(_), CArray(_): true;
};
}
function swizBits( s : Array<Comp>, t : VarType ) {
if( s == null ) return fullBits(t);
var b = 0;
for( x in s )
b |= 1 << Type.enumIndex(x);
return b;
}
function fullBits( t : VarType ) {
return (1 << Tools.floatSize(t)) - 1;
}
function compileAssign( v : Null<CodeValue>, e : CodeValue ) {
switch( e.d ) {
case CIf(cond, eif, eelse):
if( isTrue(compileCond(cond)) ) {
for( e in eif )
compileAssign(e.v, e.e);
} else if( eelse != null ) {
for( e in eelse )
compileAssign(e.v, e.e);
}
return;
case CFor(vloop, it, exprs):
switch( it.d ) {
case COp(CInterval, _first, _max):
switch( [compileCond(_first),compileCond(_max)] ) {
case [CInt(first), CInt(max)]:
var p = props(vloop);
for( i in first...max ) {
p.value = CInt(i);
p.newVar = null;
for( e in exprs )
compileAssign(e.v, e.e);
}
default:
throw "assert";
}
default:
var vit = compileValue(it);
switch( vit.d ) {
case CVar(v,_):
switch( v.type ) {
case TArray(t, size):
var v = newVar(v, v.pos);
var values = [];
if( size == 0 ) {
size = switch( compileCond(it) ) {
case CArray(vl): values = vl; vl.length;
case CNull: 0;
default: throw "assert";
}
v.type = TArray(t, size);
}
var obj = objectVars.get(v.id);
if( obj == null ) {
obj = { v : v, fields : new Map() };
objectVars.set(v.id, obj);
}
var p = props(vloop);
for( i in 0...size ) {
var vi = allocVar("$" + v.name + "#" + i, VConst, t, e.p);
vi.index = i;
obj.fields.set("" + i, vi);
p.newVar = vi;
p.value = props(vi).value = values[i];
for( e in exprs )
compileAssign(e.v, e.e);
}
return;
default:
throw "assert";
}
default:
throw "assert";
}
}
return;
case CUnop(op, _):
switch( op ) {
case CKill, CSetDepth:
addAssign(null,compileValue(e), e.p);
return;
default:
}
default:
}
if( v == null )
throw "assert "+Type.enumConstructor(e.d);
var v = compileValue(v, true);
var e = compileValue(e);
addAssign(v,e,cur.pos);
}
function compileCond( v : CodeValue ) {
var old = isCond, oldC = isConst;
isCond = true;
isConst = true;
var v = compileValue(v);
isCond = old;
isConst = oldC;
return switch( v.d ) {
case CConst(c): c;
default: throw "assert";
}
}
// don't create a const-var
function compileConstValue( v : CodeValue ) {
return switch( v.d ) {
case CConst(_): v;
default:
var old = isConst;
isConst = true;
v = compileValue(v);
isConst = old;
v;
};
}
function compileValueForce( v : CodeValue ) {
var old = isConst;
isConst = false;
v = compileValue(v);
isConst = old;
return v;
}
function newVar( v : Variable, p : Position ) {
if( isCond ) {
if( v.kind != VParam )
throw "assert";
return v;
}
if( v.id < 0 )
return v;
var p = props(v);
if( p.newVar == null ) {
var kind = v.kind;
if( kind == VParam ) kind = VConst;
p.newVar = {
id : v.id,
kind : kind,
index : 0,
name : v.name,
type : v.type,
pos : v.pos,
};
p.isVertex = cur.vertex;
usedVars.push(p.newVar);
}
return p.newVar;
}
function compare(c1:Const, c2:Const) : Null<Int> {
var f1, f2;
switch( c1 ) {
case CFloat(f): f1 = f;
case CInt(i): f1 = i;
default: return null;
}
switch( c2 ) {
case CFloat(f): f2 = f;
case CInt(i): f2 = i;
default: return null;
}
return f1 < f2 ? -1 : (f1 > f2 ? 1 : 0);
}
function floatValue(c:Const) {
return switch( c ) {
case CNull: 0.;
case CFloat(f): f;
case CInt(i): i;
default:
throw "assert";
}
}
function makeOp(op:CodeOp, e1:CodeValue, e2:CodeValue ) {
e1 = compileConstValue(e1);
e2 = compileConstValue(e2);
var c1 = switch( e1.d ) {
case CConst(c): c;
default: null;
}
var c2 = switch( e2.d ) {
case CConst(c): c;
default: null;
}
if( c1 != null && c2 != null ) {
function const(f:Float->Float->Float) {
return CConst(CFloat(f(floatValue(c1), floatValue(c2))));
}
switch( op ) {
case CEq:
return CConst(CBool(Type.enumEq(c1,c2)));
case CNeq:
return CConst(CBool(!Type.enumEq(c1,c2)));
case CLt:
var c = compare(c1, c2);
if( c != null )
return CConst(CBool(c < 0));
case CGt:
var c = compare(c1, c2);
if( c != null )
return CConst(CBool(c > 0));
case CLte:
var c = compare(c1, c2);
if( c != null )
return CConst(CBool(c <= 0));
case CGte:
var c = compare(c1, c2);
if( c != null )
return CConst(CBool(c >= 0));
case COr:
return CConst(CBool(isTrue(c1) || isTrue(c2)));
case CAnd:
return CConst(CBool(isTrue(c1) && isTrue(c2)));
case CAdd: return const(function(a, b) return a + b);
case CSub: return const(function(a, b) return a - b);
case CMul, CDot: return const(function(a, b) return a * b);
case CDiv: return const(function(a, b) return a / b);
case CPow: return const(function(a, b) return Math.pow(a, b));
case CMod: return const(function(a, b) return a % b);
case CMin: return const(function(a, b) return a < b ? a : b);
case CMax: return const(function(a, b) return a > b ? a : b);
case CCross:
case CInterval: throw "assert";
}
}
// force const building
e1 = compileValueForce(e1);
e2 = compileValueForce(e2);
return COp(op, e1, e2);
}
function makeUnop( op : CodeUnop, e : CodeValue ) {
e = compileConstValue(e);
switch( e.d ) {
case CConst(c):
function const(f:Float->Float) {
return CConst(CFloat(f(floatValue(c))));
}
switch( op ) {
case CNorm, CTrans, CKill, CSetDepth:
case CInt: return const(function(x) return Std.int(x));
case CFrac: return const(function(x) return x % 1.);
case CExp: return const(Math.exp);
case CAbs: return const(Math.abs);
case CRsq: return const(function(x) return 1 / Math.sqrt(x));
case CRcp: return const(function(x) return 1 / x);
case CLog: return const(Math.log);
case CSqrt: return const(Math.sqrt);
case CSin: return const(Math.sin);
case CCos: return const(Math.cos);
case CSat: return const(Math.cos);
case CNeg: return const(function(x) return -x);
case CLen: return const(function(x) return x);
case CNot:
return CConst(CBool(!isTrue(c)));
}
default:
}
e = compileValueForce(e);
return CUnop(op, e);
}
function compileValue( e : CodeValue, isTarget = false ) : CodeValue {
var d = switch( e.d ) {
case CConst(_):
e.d;
case CVar(v, swiz):
var v = newVar(v, e.p);
var p = props(v);
if( isCond )
CConst(p.value);
else {
if( isTarget )
p.write |= swizBits(swiz, v.type);
else
p.read = true;
CVar(v, swiz);
}
case COp(op, e1, e2):
makeOp(op, e1, e2);
case CTex(v, acc, mode):
v = newVar(v, e.p); // texture
props(v).read = true;
acc = compileValue(acc);
var flags = [];
for( m in mode )
switch( m.f ) {
case CTFlag(f): flags.push(f);
case CTParam(t, v):
var c = compileCond(v);
switch(t) {
case PWrap:
if( isTrue(c) ) flags.push(TWrap);
case PMipMap:
if( c != CNull )
flags.push(isTrue(c) ? TMipMapLinear : TMipMapNearest);
case PFilter:
if( c != CNull )
flags.push(isTrue(c) ? TFilterLinear : TFilterNearest);
case PLodBias:
switch( c ) {
case CNull:
case CInt(i):
flags.push(TLodBias(i));
case CFloat(f):
flags.push(TLodBias(f));
default:
throw "assert";
}
case PSingle:
if( isTrue(c) ) flags.push(TSingle);
case PIgnoreSampler:
if( isTrue(c) ) flags.push(TIgnoreSampler);
case PType:
var idx = switch( c ) {
case CNull: 0;
case CInt(i): i;
case CFloat(f): Std.int(f);
default: throw "assert";
}
if( idx > 0 )
flags.push([TTypeDxt1, TTypeDxt5][idx - 1]);
}
}
var mode = [];
for( f in flags )
mode.push( { f : CTFlag(f), p : e.p } );
CTex(v, acc, mode);
case CCond(c, eif, eelse):
if( isTrue(compileCond(c)) )
return compileValue(eif);
return compileValue(eelse);
case CVector(vals):
return compileVector(vals, e.p);
case CUnop(op, e):
makeUnop(op, e);
case CSwiz(v, swiz):
v = compileValue(v, isTarget);
// build swizzling
switch( v.d ) {
case CVar(v, s2):
var ns;
if( s2 == null )
ns = swiz;
else {
// combine swizzlings
ns = [];
for( s in swiz )
ns.push(s2[Type.enumIndex(s)]);
}
return { d : CVar(v, ns), t : Tools.makeFloat(swiz.length), p : e.p };
default:
return { d : CSwiz(v, swiz), t : Tools.makeFloat(swiz.length), p : e.p };
}
case CRow(v, index):
v = compileValue(v);
index = compileValue(index);
switch( v.d ) {
case CVar(v, swiz):
if( swiz == null )
switch( v.type ) {
case TArray(t, _):
v = newVar(v, e.p);
props(v).read = true;
return { d : CAccess(v, index), t : t, p : e.p };
default:
}
default:
}
throw "assert row " + v;
case CAccess(v, idx):
v = newVar(v, e.p);
props(v).read = true;
idx = compileValue(idx);
return { d : CAccess(v, idx), t : e.t, p : e.p };
case CSubBlock(tmp, v):
var exprs = cur.exprs;
cur.exprs = [];
for( e in tmp )
compileAssign(e.v, e.e);
var tmp = cur.exprs;
cur.exprs = exprs;
return { d : CSubBlock(tmp, compileValue(v)), t : e.t, p : e.p };
case CField(v, f):
v = compileValue(v, isTarget);
switch( v.d ) {
case CVar(v, _):
var obj = objectVars.get(v.id);
if( obj == null ) {
obj = { v : v, fields : new Map() };
objectVars.set(v.id, obj);
}
var v2 = obj.fields.get(f);
if( v2 == null ) {
v2 = allocVar("$" + v.name + "." + f, v.kind, e.t, e.p);
obj.fields.set(f, v2);
}
return { d : CVar(v2, null), t : v2.type, p : e.p };
case CConst(CNull):
return v;
case CConst(CObject(fl)):
var val = fl.get(f);
var ft = TNull;
switch( v.t ) {
case TObject(fl):
for( fi in fl )
if( fi.name == f ) {
ft = fi.t;
break;
}
default:
}
return v == null ? { d : CConst(CNull), t : TNull, p : e.p } : { d : CConst(val), t : ft, p : e.p };
default:
throw "assert";
}
default:
throw "assert "+Type.enumConstructor(e.d);
}
// translate the constant to the corresponding variable value
if( !isConst )
switch( d ) {
case CConst(c):
d = allocConst([floatValue(c)], e.p).d;
default:
}
return { d : d, t : e.t, p : e.p };
}
function compileVector(values:Array<CodeValue>, p) {
if( values.length == 0 || values.length > 4 )
throw "assert";
var consts = [];
var exprs = [];
for( i in 0...values.length ) {
var e = compileConstValue(values[i]);
switch( e.d ) {
case CConst(c):
consts.push(floatValue(c));
default:
exprs[i] = e;
}
}
// all values are constants
if( consts.length == values.length )
return allocConst(consts, p);
// declare a new temporary
var v = allocVar("$tmp" + Lambda.count(varProps), VTmp, Tools.makeFloat(values.length), p);
usedVars.push(v);
// assign expressions first
var old = cur.exprs;
cur.exprs = [];
var write = [];
for( i in 0...values.length ) {
var e = exprs[i];
var c = [X, Y, Z, W][i];
if( e == null ) {
write.push(c);
continue;
}
addAssign( { d : CVar(v, [c]), t : TFloat, p : e.p }, e, p);
}
// assign constants if any
if( write.length > 0 ) {
if( isUnsupportedWriteMask(write) )
for( i in 0...write.length )
addAssign( { d : CVar(v, [write[i]]), t : TFloat, p : p }, allocConst([consts[i]], p), p);
else
addAssign( { d : CVar(v, write), t : Tools.makeFloat(write.length), p : p }, allocConst(consts, p), p);
}
// return temporary
var ret = { d : CVar(v), t : v.type, p : p };
var sub = { d : CSubBlock(cur.exprs, ret), t : ret.t, p : p };
cur.exprs = old;
return sub;
}
}