forked from LeenkxTeam/LNXSDK
Update Files
This commit is contained in:
509
lib/haxerecast/Sources/webidl/Parser.hx
Normal file
509
lib/haxerecast/Sources/webidl/Parser.hx
Normal file
@ -0,0 +1,509 @@
|
||||
package webidl;
|
||||
import webidl.Data;
|
||||
|
||||
private enum Token {
|
||||
TEof;
|
||||
TId( s : String );
|
||||
TPOpen;
|
||||
TPClose;
|
||||
TBrOpen;
|
||||
TBrClose;
|
||||
TBkOpen;
|
||||
TBkClose;
|
||||
TSemicolon;
|
||||
TComma;
|
||||
TOp( op : String );
|
||||
TString( str : String );
|
||||
}
|
||||
|
||||
|
||||
class Parser {
|
||||
|
||||
public var line : Int;
|
||||
var input : haxe.io.Input;
|
||||
var char : Int;
|
||||
var ops : Array<Bool>;
|
||||
var idents : Array<Bool>;
|
||||
var tokens : Array<Token>;
|
||||
var pos = 0;
|
||||
var fileName : String;
|
||||
|
||||
public function new() {
|
||||
var opChars = "+*/-=!><&|^%~";
|
||||
var identChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_";
|
||||
idents = new Array();
|
||||
ops = new Array();
|
||||
for( i in 0...identChars.length )
|
||||
idents[identChars.charCodeAt(i)] = true;
|
||||
for( i in 0...opChars.length )
|
||||
ops[opChars.charCodeAt(i)] = true;
|
||||
}
|
||||
|
||||
public function parseFile( fileName : String, input : haxe.io.Input ) {
|
||||
this.fileName = fileName;
|
||||
pos = 0;
|
||||
line = 1;
|
||||
char = -1;
|
||||
tokens = [];
|
||||
this.input = input;
|
||||
var out = [];
|
||||
while( true ) {
|
||||
var tk = token();
|
||||
if( tk == TEof ) break;
|
||||
push(tk);
|
||||
out.push(parseDecl());
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
function parseDecl() {
|
||||
var attr = attributes();
|
||||
var pmin = this.pos;
|
||||
switch( token() ) {
|
||||
case TId("interface"):
|
||||
var name = ident();
|
||||
ensure(TBrOpen);
|
||||
var fields = [];
|
||||
while( true ) {
|
||||
var tk = token();
|
||||
if( tk == TBrClose ) break;
|
||||
push(tk);
|
||||
fields.push(parseField());
|
||||
}
|
||||
ensure(TSemicolon);
|
||||
return { pos : makePos(pmin), kind : DInterface(name, attr, fields) };
|
||||
case TId("enum"):
|
||||
var name = ident();
|
||||
ensure(TBrOpen);
|
||||
var values = [];
|
||||
if( !maybe(TBrClose) )
|
||||
while( true ) {
|
||||
switch( token() ) {
|
||||
case TString(str): values.push(str);
|
||||
case var tk: unexpected(tk);
|
||||
}
|
||||
switch( token() ) {
|
||||
case TBrClose: break;
|
||||
case TComma: continue;
|
||||
case var tk: unexpected(tk);
|
||||
}
|
||||
}
|
||||
ensure(TSemicolon);
|
||||
return { pos : makePos(pmin), kind : DEnum(name, values) };
|
||||
case TId(name):
|
||||
if( attr.length > 0 )
|
||||
throw "assert";
|
||||
ensure(TId("implements"));
|
||||
var intf = ident();
|
||||
ensure(TSemicolon);
|
||||
return { pos : makePos(pmin), kind : DImplements(name, intf) };
|
||||
|
||||
case var tk:
|
||||
return unexpected(tk);
|
||||
}
|
||||
}
|
||||
|
||||
function attributes() {
|
||||
if( !maybe(TBkOpen) )
|
||||
return [];
|
||||
var attrs = [];
|
||||
while( true ) {
|
||||
var attr = switch( ident() ) {
|
||||
case "Value": AValue;
|
||||
case "Ref": ARef;
|
||||
case "Const": AConst;
|
||||
case "NoDelete": ANoDelete;
|
||||
case "Prefix":
|
||||
ensure(TOp("="));
|
||||
APrefix(switch( token() ) { case TString(s): s; case var tk: unexpected(tk); });
|
||||
case "JSImplementation":
|
||||
ensure(TOp("="));
|
||||
AJSImplementation(switch( token() ) { case TString(s): s; case var tk: unexpected(tk); });
|
||||
case "Operator":
|
||||
ensure(TOp("="));
|
||||
AOperator(switch( token() ) { case TString(s): s; case var tk: unexpected(tk); });
|
||||
case var attr:
|
||||
error("Unsupported attribute " + attr);
|
||||
null;
|
||||
}
|
||||
attrs.push(attr);
|
||||
if( !maybe(TComma) ) break;
|
||||
}
|
||||
ensure(TBkClose);
|
||||
return attrs;
|
||||
}
|
||||
|
||||
function type() : Type {
|
||||
var id = ident();
|
||||
var t = switch( id ) {
|
||||
case "void": TVoid;
|
||||
case "float": TFloat;
|
||||
case "double": TDouble;
|
||||
case "long", "int": TInt; // long ensures 32 bits
|
||||
case "short": TShort;
|
||||
case "boolean", "bool": TBool;
|
||||
case "any": TAny;
|
||||
case "VoidPtr": TVoidPtr;
|
||||
default: TCustom(id);
|
||||
};
|
||||
if( maybe(TBkOpen) ) {
|
||||
ensure(TBkClose);
|
||||
t = TArray(t);
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
function makePos( pmin : Int ) {
|
||||
return { file : fileName, line : line, pos : pmin };
|
||||
}
|
||||
|
||||
function parseField() : Field {
|
||||
var attr = attributes();
|
||||
var pmin = this.pos;
|
||||
|
||||
if( maybe(TId("attribute")) ) {
|
||||
var t = type();
|
||||
var name = ident();
|
||||
ensure(TSemicolon);
|
||||
return { name : name, kind : FAttribute({ t : t, attr : attr }), pos : makePos(pmin) };
|
||||
}
|
||||
|
||||
if( maybe(TId("const")) ) {
|
||||
var type = type();
|
||||
var name = ident();
|
||||
ensure(TOp("="));
|
||||
var value = tokenString(token());
|
||||
ensure(TSemicolon);
|
||||
return { name: name, kind : DConst(name, type, value), pos : makePos(pmin) };
|
||||
}
|
||||
|
||||
var tret = type();
|
||||
var name = ident();
|
||||
ensure(TPOpen);
|
||||
var args = [];
|
||||
if( !maybe(TPClose) ) {
|
||||
while( true ) {
|
||||
var attr = attributes();
|
||||
var opt = maybe(TId("optional"));
|
||||
var t = type();
|
||||
var name = ident();
|
||||
args.push({ name : name, t : { t : t, attr : attr }, opt : opt });
|
||||
switch( token() ) {
|
||||
case TPClose:
|
||||
break;
|
||||
case TComma:
|
||||
continue;
|
||||
case var tk:
|
||||
unexpected(tk);
|
||||
}
|
||||
}
|
||||
}
|
||||
ensure(TSemicolon);
|
||||
return { name : name, kind : FMethod(args, { attr : attr, t : tret }), pos : makePos(pmin) };
|
||||
}
|
||||
|
||||
// --- Lexing
|
||||
|
||||
function invalidChar(c:Int) {
|
||||
error("Invalid char "+c+"("+String.fromCharCode(c)+")");
|
||||
}
|
||||
|
||||
function error( msg : String ) {
|
||||
throw msg+" line "+line;
|
||||
}
|
||||
|
||||
function unexpected( tk ) : Dynamic {
|
||||
error("Unexpected " + tokenString(tk));
|
||||
return null;
|
||||
}
|
||||
|
||||
function tokenString( tk ) {
|
||||
return switch( tk ) {
|
||||
case TEof: "<eof>";
|
||||
case TId(id): id;
|
||||
case TPOpen: "(";
|
||||
case TPClose: ")";
|
||||
case TBkOpen: "[";
|
||||
case TBkClose: "]";
|
||||
case TBrOpen: "{";
|
||||
case TBrClose: "}";
|
||||
case TComma: ",";
|
||||
case TSemicolon: ";";
|
||||
case TOp(op): op;
|
||||
case TString(str): '"' + str + '"';
|
||||
}
|
||||
}
|
||||
|
||||
inline function push(tk) {
|
||||
tokens.push(tk);
|
||||
}
|
||||
|
||||
function ensure(tk) {
|
||||
var t = token();
|
||||
if( t != tk && !std.Type.enumEq(t,tk) ) unexpected(t);
|
||||
}
|
||||
|
||||
function maybe(tk) {
|
||||
var t = token();
|
||||
if( t == tk || std.Type.enumEq(t,tk) )
|
||||
return true;
|
||||
push(t);
|
||||
return false;
|
||||
}
|
||||
|
||||
function ident() {
|
||||
var tk = token();
|
||||
switch( tk ) {
|
||||
case TId(id): return id;
|
||||
default:
|
||||
unexpected(tk);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function readChar() {
|
||||
pos++;
|
||||
return try input.readByte() catch( e : Dynamic ) 0;
|
||||
}
|
||||
|
||||
function token() : Token {
|
||||
if( tokens.length > 0 )
|
||||
return tokens.shift();
|
||||
var char;
|
||||
if( this.char < 0 )
|
||||
char = readChar();
|
||||
else {
|
||||
char = this.char;
|
||||
this.char = -1;
|
||||
}
|
||||
while( true ) {
|
||||
switch( char ) {
|
||||
case 0: return TEof;
|
||||
case 32,9,13: // space, tab, CR
|
||||
case 10: line++; // LF
|
||||
/* case 48,49,50,51,52,53,54,55,56,57: // 0...9
|
||||
var n = (char - 48) * 1.0;
|
||||
var exp = 0.;
|
||||
while( true ) {
|
||||
char = readChar();
|
||||
exp *= 10;
|
||||
switch( char ) {
|
||||
case 48,49,50,51,52,53,54,55,56,57:
|
||||
n = n * 10 + (char - 48);
|
||||
case 46:
|
||||
if( exp > 0 ) {
|
||||
// in case of '...'
|
||||
if( exp == 10 && readChar() == 46 ) {
|
||||
push(TOp("..."));
|
||||
var i = Std.int(n);
|
||||
return TConst( (i == n) ? CInt(i) : CFloat(n) );
|
||||
}
|
||||
invalidChar(char);
|
||||
}
|
||||
exp = 1.;
|
||||
case 120: // x
|
||||
if( n > 0 || exp > 0 )
|
||||
invalidChar(char);
|
||||
// read hexa
|
||||
#if haxe3
|
||||
var n = 0;
|
||||
while( true ) {
|
||||
char = readChar();
|
||||
switch( char ) {
|
||||
case 48,49,50,51,52,53,54,55,56,57: // 0-9
|
||||
n = (n << 4) + char - 48;
|
||||
case 65,66,67,68,69,70: // A-F
|
||||
n = (n << 4) + (char - 55);
|
||||
case 97,98,99,100,101,102: // a-f
|
||||
n = (n << 4) + (char - 87);
|
||||
default:
|
||||
this.char = char;
|
||||
return TConst(CInt(n));
|
||||
}
|
||||
}
|
||||
#else
|
||||
var n = haxe.Int32.ofInt(0);
|
||||
while( true ) {
|
||||
char = readChar();
|
||||
switch( char ) {
|
||||
case 48,49,50,51,52,53,54,55,56,57: // 0-9
|
||||
n = haxe.Int32.add(haxe.Int32.shl(n,4), cast (char - 48));
|
||||
case 65,66,67,68,69,70: // A-F
|
||||
n = haxe.Int32.add(haxe.Int32.shl(n,4), cast (char - 55));
|
||||
case 97,98,99,100,101,102: // a-f
|
||||
n = haxe.Int32.add(haxe.Int32.shl(n,4), cast (char - 87));
|
||||
default:
|
||||
this.char = char;
|
||||
// we allow to parse hexadecimal Int32 in Neko, but when the value will be
|
||||
// evaluated by Interpreter, a failure will occur if no Int32 operation is
|
||||
// performed
|
||||
var v = try CInt(haxe.Int32.toInt(n)) catch( e : Dynamic ) CInt32(n);
|
||||
return TConst(v);
|
||||
}
|
||||
}
|
||||
#end
|
||||
default:
|
||||
this.char = char;
|
||||
var i = Std.int(n);
|
||||
return TConst( (exp > 0) ? CFloat(n * 10 / exp) : ((i == n) ? CInt(i) : CFloat(n)) );
|
||||
}
|
||||
}*/
|
||||
case 59: return TSemicolon;
|
||||
case 40: return TPOpen;
|
||||
case 41: return TPClose;
|
||||
case 44: return TComma;
|
||||
/* case 46:
|
||||
char = readChar();
|
||||
switch( char ) {
|
||||
case 48,49,50,51,52,53,54,55,56,57:
|
||||
var n = char - 48;
|
||||
var exp = 1;
|
||||
while( true ) {
|
||||
char = readChar();
|
||||
exp *= 10;
|
||||
switch( char ) {
|
||||
case 48,49,50,51,52,53,54,55,56,57:
|
||||
n = n * 10 + (char - 48);
|
||||
default:
|
||||
this.char = char;
|
||||
return TConst( CFloat(n/exp) );
|
||||
}
|
||||
}
|
||||
case 46:
|
||||
char = readChar();
|
||||
if( char != 46 )
|
||||
invalidChar(char);
|
||||
return TOp("...");
|
||||
default:
|
||||
this.char = char;
|
||||
return TDot;
|
||||
}*/
|
||||
case 123: return TBrOpen;
|
||||
case 125: return TBrClose;
|
||||
case 91: return TBkOpen;
|
||||
case 93: return TBkClose;
|
||||
case 39: return TString(readString(39));
|
||||
case 34: return TString(readString(34));
|
||||
// case 63: return TQuestion;
|
||||
// case 58: return TDoubleDot;
|
||||
case '='.code:
|
||||
char = readChar();
|
||||
if( char == '='.code )
|
||||
return TOp("==");
|
||||
else if ( char == '>'.code )
|
||||
return TOp("=>");
|
||||
this.char = char;
|
||||
return TOp("=");
|
||||
default:
|
||||
if( ops[char] ) {
|
||||
var op = String.fromCharCode(char);
|
||||
var prev = -1;
|
||||
while( true ) {
|
||||
char = readChar();
|
||||
if( !ops[char] || prev == '='.code ) {
|
||||
if( op.charCodeAt(0) == '/'.code )
|
||||
return tokenComment(op,char);
|
||||
this.char = char;
|
||||
return TOp(op);
|
||||
}
|
||||
prev = char;
|
||||
op += String.fromCharCode(char);
|
||||
}
|
||||
}
|
||||
if( idents[char] ) {
|
||||
var id = String.fromCharCode(char);
|
||||
while( true ) {
|
||||
char = readChar();
|
||||
if( !idents[char] ) {
|
||||
this.char = char;
|
||||
return TId(id);
|
||||
}
|
||||
id += String.fromCharCode(char);
|
||||
}
|
||||
}
|
||||
invalidChar(char);
|
||||
}
|
||||
char = readChar();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function tokenComment( op : String, char : Int ) {
|
||||
var c = op.charCodeAt(1);
|
||||
var s = input;
|
||||
if( c == '/'.code ) { // comment
|
||||
try {
|
||||
while( char != '\r'.code && char != '\n'.code ) {
|
||||
pos++;
|
||||
char = s.readByte();
|
||||
}
|
||||
this.char = char;
|
||||
} catch( e : Dynamic ) {
|
||||
}
|
||||
return token();
|
||||
}
|
||||
if( c == '*'.code ) { /* comment */
|
||||
var old = line;
|
||||
if( op == "/**/" ) {
|
||||
this.char = char;
|
||||
return token();
|
||||
}
|
||||
try {
|
||||
while( true ) {
|
||||
while( char != '*'.code ) {
|
||||
if( char == '\n'.code ) line++;
|
||||
pos++;
|
||||
char = s.readByte();
|
||||
}
|
||||
pos++;
|
||||
char = s.readByte();
|
||||
if( char == '/'.code )
|
||||
break;
|
||||
}
|
||||
} catch( e : Dynamic ) {
|
||||
line = old;
|
||||
error("Unterminated comment");
|
||||
}
|
||||
return token();
|
||||
}
|
||||
this.char = char;
|
||||
return TOp(op);
|
||||
}
|
||||
|
||||
function readString( until ) {
|
||||
var c = 0;
|
||||
var b = new haxe.io.BytesOutput();
|
||||
var esc = false;
|
||||
var old = line;
|
||||
var s = input;
|
||||
while( true ) {
|
||||
try {
|
||||
pos++;
|
||||
c = s.readByte();
|
||||
} catch( e : Dynamic ) {
|
||||
line = old;
|
||||
error("Unterminated string");
|
||||
}
|
||||
if( esc ) {
|
||||
esc = false;
|
||||
switch( c ) {
|
||||
case 'n'.code: b.writeByte(10);
|
||||
case 'r'.code: b.writeByte(13);
|
||||
case 't'.code: b.writeByte(9);
|
||||
case "'".code, '"'.code, '\\'.code: b.writeByte(c);
|
||||
case '/'.code: b.writeByte(c);
|
||||
default: invalidChar(c);
|
||||
}
|
||||
} else if( c == 92 )
|
||||
esc = true;
|
||||
else if( c == until )
|
||||
break;
|
||||
else {
|
||||
if( c == 10 ) line++;
|
||||
b.writeByte(c);
|
||||
}
|
||||
}
|
||||
return b.getBytes().toString();
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user