forked from LeenkxTeam/LNXSDK
519 lines
12 KiB
Haxe
519 lines
12 KiB
Haxe
/*
|
|
* Copyright (C)2008-2017 Haxe Foundation
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
* copy of this software and associated documentation files (the "Software"),
|
|
* to deal in the Software without restriction, including without limitation
|
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
* and/or sell copies of the Software, and to permit persons to whom the
|
|
* Software is furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in
|
|
* all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
* DEALINGS IN THE SOFTWARE.
|
|
*/
|
|
package hscript;
|
|
import hscript.Expr;
|
|
|
|
class Bytes {
|
|
|
|
var bin : haxe.io.Bytes;
|
|
var bout : haxe.io.BytesBuffer;
|
|
var pin : Int;
|
|
var hstrings : Map<String,Int>;
|
|
var strings : Array<String>;
|
|
var nstrings : Int;
|
|
|
|
public var storeTypes : Bool = false;
|
|
|
|
function new( ?bin ) {
|
|
this.bin = bin;
|
|
pin = 0;
|
|
bout = new haxe.io.BytesBuffer();
|
|
hstrings = new Map();
|
|
strings = [null];
|
|
nstrings = 1;
|
|
}
|
|
|
|
function doEncodeString( v : String ) {
|
|
var vid = hstrings.get(v);
|
|
if( vid == null ) {
|
|
if( nstrings == 256 ) {
|
|
hstrings = new Map();
|
|
nstrings = 1;
|
|
}
|
|
hstrings.set(v,nstrings);
|
|
bout.addByte(0);
|
|
var vb = haxe.io.Bytes.ofString(v);
|
|
bout.addByte(vb.length);
|
|
bout.add(vb);
|
|
nstrings++;
|
|
} else
|
|
bout.addByte(vid);
|
|
}
|
|
|
|
function doDecodeString() {
|
|
var id = bin.get(pin++);
|
|
if( id == 0 ) {
|
|
var len = bin.get(pin);
|
|
var str = #if (haxe_ver < 3.103) bin.readString(pin+1,len); #else bin.getString(pin+1,len); #end
|
|
pin += len + 1;
|
|
if( strings.length == 255 )
|
|
strings = [null];
|
|
strings.push(str);
|
|
return str;
|
|
}
|
|
return strings[id];
|
|
}
|
|
|
|
function doEncodeInt(v: Int) {
|
|
bout.addInt32(v);
|
|
}
|
|
|
|
function doEncodeConst( c : Const ) {
|
|
switch( c ) {
|
|
case CInt(v):
|
|
if( v >= 0 && v <= 255 ) {
|
|
bout.addByte(0);
|
|
bout.addByte(v);
|
|
} else {
|
|
bout.addByte(1);
|
|
doEncodeInt(v);
|
|
}
|
|
case CFloat(f):
|
|
bout.addByte(2);
|
|
doEncodeString(Std.string(f));
|
|
case CString(s):
|
|
bout.addByte(3);
|
|
doEncodeString(s);
|
|
}
|
|
}
|
|
|
|
function doDecodeInt() {
|
|
var i = bin.getInt32(pin);
|
|
pin += 4;
|
|
return i;
|
|
}
|
|
|
|
function doDecodeConst() {
|
|
return switch( bin.get(pin++) ) {
|
|
case 0:
|
|
CInt(bin.get(pin++));
|
|
case 1:
|
|
var i = doDecodeInt();
|
|
CInt(i);
|
|
case 2:
|
|
CFloat( Std.parseFloat(doDecodeString()) );
|
|
case 3:
|
|
CString( doDecodeString() );
|
|
default:
|
|
throw "Invalid code "+bin.get(pin-1);
|
|
}
|
|
}
|
|
|
|
function doEncode( e : Expr ) {
|
|
#if hscriptPos
|
|
doEncodeString(e.origin);
|
|
doEncodeInt(e.line);
|
|
var e = e.e;
|
|
#end
|
|
bout.addByte(exprIndex(e));
|
|
switch( e ) {
|
|
case EConst(c):
|
|
doEncodeConst(c);
|
|
case EIdent(v):
|
|
doEncodeString(v);
|
|
case EVar(n,t,e):
|
|
doEncodeString(n);
|
|
encodeType(t);
|
|
if( e == null )
|
|
bout.addByte(255);
|
|
else
|
|
doEncode(e);
|
|
case EParent(e):
|
|
doEncode(e);
|
|
case EBlock(el):
|
|
bout.addByte(el.length);
|
|
for( e in el )
|
|
doEncode(e);
|
|
case EField(e,f):
|
|
doEncode(e);
|
|
doEncodeString(f);
|
|
case EBinop(op,e1,e2):
|
|
doEncodeString(op);
|
|
doEncode(e1);
|
|
doEncode(e2);
|
|
case EUnop(op,prefix,e):
|
|
doEncodeString(op);
|
|
bout.addByte(prefix?1:0);
|
|
doEncode(e);
|
|
case ECall(e,el):
|
|
doEncode(e);
|
|
bout.addByte(el.length);
|
|
for( e in el )
|
|
doEncode(e);
|
|
case EIf(cond,e1,e2):
|
|
doEncode(cond);
|
|
doEncode(e1);
|
|
if( e2 == null )
|
|
bout.addByte(255);
|
|
else
|
|
doEncode(e2);
|
|
case EWhile(cond,e):
|
|
doEncode(cond);
|
|
doEncode(e);
|
|
case EDoWhile(cond,e):
|
|
doEncode(cond);
|
|
doEncode(e);
|
|
case EFor(v,it,e):
|
|
doEncodeString(v);
|
|
doEncode(it);
|
|
doEncode(e);
|
|
case EForGen(it,e):
|
|
doEncode(it);
|
|
doEncode(e);
|
|
case EBreak, EContinue:
|
|
case EFunction(params,e,name,t):
|
|
bout.addByte(params.length);
|
|
for( p in params )
|
|
doEncodeString(p.name);
|
|
doEncode(e);
|
|
doEncodeString(name == null?"":name);
|
|
encodeType(t);
|
|
case EReturn(e):
|
|
if( e == null )
|
|
bout.addByte(255);
|
|
else
|
|
doEncode(e);
|
|
case EArray(e,index):
|
|
doEncode(e);
|
|
doEncode(index);
|
|
case EArrayDecl(el):
|
|
if( el.length >= 255 ) throw "assert";
|
|
bout.addByte(el.length);
|
|
for( e in el )
|
|
doEncode(e);
|
|
case ENew(cl,params):
|
|
doEncodeString(cl);
|
|
bout.addByte(params.length);
|
|
for( e in params )
|
|
doEncode(e);
|
|
case EThrow(e):
|
|
doEncode(e);
|
|
case ETry(e,v,t,ecatch):
|
|
doEncode(e);
|
|
doEncodeString(v);
|
|
encodeType(t);
|
|
doEncode(ecatch);
|
|
case EObject(fl):
|
|
bout.addByte(fl.length);
|
|
for( f in fl ) {
|
|
doEncodeString(f.name);
|
|
doEncode(f.e);
|
|
}
|
|
case ETernary(cond, e1, e2):
|
|
doEncode(cond);
|
|
doEncode(e1);
|
|
doEncode(e2);
|
|
case ESwitch(e, cases, def):
|
|
doEncode(e);
|
|
for( c in cases ) {
|
|
if( c.values.length == 0 ) throw "assert";
|
|
for( v in c.values )
|
|
doEncode(v);
|
|
bout.addByte(255);
|
|
doEncode(c.expr);
|
|
}
|
|
bout.addByte(255);
|
|
if( def == null ) bout.addByte(255) else doEncode(def);
|
|
case EMeta(name,args,e):
|
|
doEncodeString(name);
|
|
bout.addByte(args == null ? 0 : args.length + 1);
|
|
if( args != null ) for( e in args ) doEncode(e);
|
|
doEncode(e);
|
|
case ECheckType(e,t):
|
|
doEncode(e);
|
|
encodeType(t);
|
|
case ECast(e, t):
|
|
doEncode(e);
|
|
encodeType(t);
|
|
}
|
|
}
|
|
|
|
function encodeType( t : CType ) {
|
|
if( !storeTypes )
|
|
return;
|
|
if( t == null ) {
|
|
bout.addByte(255);
|
|
return;
|
|
}
|
|
bout.addByte(t.getIndex());
|
|
switch( t ) {
|
|
case CTPath(path, params):
|
|
doEncodeString(path.join("."));
|
|
if( params == null )
|
|
bout.addByte(255);
|
|
else {
|
|
bout.addByte(params.length);
|
|
for( p in params )
|
|
encodeType(p);
|
|
}
|
|
case CTFun(args, ret):
|
|
bout.addByte(args.length);
|
|
for( a in args )
|
|
encodeType(a);
|
|
encodeType(ret);
|
|
case CTAnon(fields):
|
|
doEncodeInt(fields.length);
|
|
for( f in fields ) {
|
|
doEncodeString(f.name);
|
|
encodeType(f.t);
|
|
if( f.meta == null )
|
|
bout.addByte(255);
|
|
else {
|
|
bout.addByte(f.meta.length);
|
|
for( m in f.meta ) {
|
|
doEncodeString(m.name);
|
|
doEncodeInt(m.params.length);
|
|
for( p in m.params )
|
|
doEncode(p);
|
|
}
|
|
}
|
|
}
|
|
case CTParent(t):
|
|
encodeType(t);
|
|
case CTOpt(t):
|
|
encodeType(t);
|
|
case CTNamed(n, t):
|
|
doEncodeString(n);
|
|
encodeType(t);
|
|
case CTExpr(e):
|
|
doEncode(e);
|
|
}
|
|
}
|
|
|
|
function exprIndex(e):Int {
|
|
return switch (e) {
|
|
case EConst(_): 0;
|
|
case EIdent(_): 1;
|
|
case EVar(_): 2;
|
|
case EParent(_): 3;
|
|
case EBlock(_): 4;
|
|
case EField(_): 5;
|
|
case EBinop(_): 6;
|
|
case EUnop(_): 7;
|
|
case ECall(_): 8;
|
|
case EIf(_): 9;
|
|
case EWhile(_): 10;
|
|
case EFor(_): 11;
|
|
case EBreak: 12;
|
|
case EContinue: 13;
|
|
case EFunction(_): 14;
|
|
case EReturn(_): 15;
|
|
case EArray(_): 16;
|
|
case EArrayDecl(_): 17;
|
|
case ENew(_): 18;
|
|
case EThrow(_): 19;
|
|
case ETry(_): 20;
|
|
case EObject(_): 21;
|
|
case ETernary(_): 22;
|
|
case ESwitch(_): 23;
|
|
case EDoWhile(_): 24;
|
|
case EMeta(_): 25;
|
|
case ECheckType(_): 26;
|
|
case EForGen(_): 27;
|
|
case ECast(_): 28;
|
|
}
|
|
}
|
|
|
|
function doDecode() : Expr {
|
|
#if hscriptPos
|
|
if( getByte() == 255 )
|
|
return null;
|
|
pin--;
|
|
var origin = doDecodeString();
|
|
var line = doDecodeInt();
|
|
return { e : _doDecode(), pmin : 0, pmax : 0, origin : origin, line : line };
|
|
}
|
|
function _doDecode() : ExprDef {
|
|
#end
|
|
return switch( getByte() ) {
|
|
case 0:
|
|
EConst( doDecodeConst() );
|
|
case 1:
|
|
EIdent( doDecodeString() );
|
|
case 2:
|
|
var v = doDecodeString();
|
|
EVar(v,decodeType(),doDecode());
|
|
case 3:
|
|
EParent(doDecode());
|
|
case 4:
|
|
var a = new Array();
|
|
for( i in 0...getByte() )
|
|
a.push(doDecode());
|
|
EBlock(a);
|
|
case 5:
|
|
var e = doDecode();
|
|
EField(e,doDecodeString());
|
|
case 6:
|
|
var op = doDecodeString();
|
|
var e1 = doDecode();
|
|
EBinop(op,e1,doDecode());
|
|
case 7:
|
|
var op = doDecodeString();
|
|
var prefix = getByte() != 0;
|
|
EUnop(op,prefix,doDecode());
|
|
case 8:
|
|
var e = doDecode();
|
|
var params = new Array();
|
|
for( i in 0...getByte() )
|
|
params.push(doDecode());
|
|
ECall(e,params);
|
|
case 9:
|
|
var cond = doDecode();
|
|
var e1 = doDecode();
|
|
EIf(cond,e1,doDecode());
|
|
case 10:
|
|
var cond = doDecode();
|
|
EWhile(cond,doDecode());
|
|
case 11:
|
|
var v = doDecodeString();
|
|
var it = doDecode();
|
|
EFor(v,it,doDecode());
|
|
case 12:
|
|
EBreak;
|
|
case 13:
|
|
EContinue;
|
|
case 14:
|
|
var params = new Array<Argument>();
|
|
for( i in 0...getByte() )
|
|
params.push({ name : doDecodeString() });
|
|
var e = doDecode();
|
|
var name = doDecodeString();
|
|
EFunction(params,e,(name == "") ? null: name,decodeType());
|
|
case 15:
|
|
EReturn(doDecode());
|
|
case 16:
|
|
var e = doDecode();
|
|
EArray(e,doDecode());
|
|
case 17:
|
|
var el = new Array();
|
|
for( i in 0...getByte() )
|
|
el.push(doDecode());
|
|
EArrayDecl(el);
|
|
case 18:
|
|
var cl = doDecodeString();
|
|
var el = new Array();
|
|
for( i in 0...getByte() )
|
|
el.push(doDecode());
|
|
ENew(cl,el);
|
|
case 19:
|
|
EThrow(doDecode());
|
|
case 20:
|
|
var e = doDecode();
|
|
var v = doDecodeString();
|
|
ETry(e,v,decodeType(),doDecode());
|
|
case 21:
|
|
var fl = new Array();
|
|
for( i in 0...getByte() ) {
|
|
var name = doDecodeString();
|
|
var e = doDecode();
|
|
fl.push({ name : name, e : e });
|
|
}
|
|
EObject(fl);
|
|
case 22:
|
|
var cond = doDecode();
|
|
var e1 = doDecode();
|
|
var e2 = doDecode();
|
|
ETernary(cond, e1, e2);
|
|
case 23:
|
|
var e = doDecode();
|
|
var cases = [];
|
|
while( true ) {
|
|
var v = doDecode();
|
|
if( v == null ) break;
|
|
var values = [v];
|
|
while( true ) {
|
|
v = doDecode();
|
|
if( v == null ) break;
|
|
values.push(v);
|
|
}
|
|
cases.push( { values : values, expr : doDecode() } );
|
|
}
|
|
var def = doDecode();
|
|
ESwitch(e, cases, def);
|
|
case 24:
|
|
var cond = doDecode();
|
|
EDoWhile(cond,doDecode());
|
|
case 25:
|
|
var name = doDecodeString();
|
|
var count = getByte();
|
|
var args = count == 0 ? null : [for( i in 0...count - 1 ) doDecode()];
|
|
EMeta(name, args, doDecode());
|
|
case 26:
|
|
ECheckType(doDecode(), decodeType());
|
|
case 27:
|
|
EForGen(doDecode(), doDecode());
|
|
case 28:
|
|
ECast(doDecode(), decodeType());
|
|
case 255:
|
|
null;
|
|
default:
|
|
throw "Invalid code "+bin.get(pin - 1);
|
|
}
|
|
}
|
|
|
|
inline function getByte() {
|
|
return bin.get(pin++);
|
|
}
|
|
|
|
function decodeType() : CType {
|
|
if( !storeTypes )
|
|
return null;
|
|
return switch( getByte() ) {
|
|
case 255: null;
|
|
case 0:
|
|
var path = doDecodeString().split(".");
|
|
var plen = getByte();
|
|
var params = plen == 255 ? null : [for( i in 0...plen ) decodeType()];
|
|
CTPath(path, params);
|
|
case 1:
|
|
CTFun([for( v in 0...getByte() ) decodeType()], decodeType());
|
|
case 2:
|
|
CTAnon([for( v in 0...doDecodeInt() ) { name : doDecodeString(), t : decodeType(), meta : {
|
|
var v = getByte();
|
|
if( v == 255 ) null else [for( i in 0...v ) { name : doDecodeString(), params : [for( i in 0...getByte() ) doDecode()] }];
|
|
}}]);
|
|
case 3:
|
|
CTParent(decodeType());
|
|
case 4:
|
|
CTOpt(decodeType());
|
|
case 5:
|
|
CTNamed(doDecodeString(),decodeType());
|
|
case 6:
|
|
CTExpr(doDecode());
|
|
default:
|
|
throw "Invalid code "+bin.get(pin - 1);
|
|
}
|
|
}
|
|
|
|
public static function encode( e : Expr ) : haxe.io.Bytes {
|
|
var b = new Bytes();
|
|
b.doEncode(e);
|
|
return b.bout.getBytes();
|
|
}
|
|
|
|
public static function decode( bytes : haxe.io.Bytes ) : Expr {
|
|
var b = new Bytes(bytes);
|
|
return b.doDecode();
|
|
}
|
|
|
|
}
|