|
@@ -5,23 +5,79 @@ unit watparser;
|
|
interface
|
|
interface
|
|
|
|
|
|
uses
|
|
uses
|
|
- SysUtils, Classes, parseutils, wasmtext, wasmmodule, wasmbin, watscanner;
|
|
|
|
|
|
+ SysUtils, Classes, wasmtext, wasmmodule, wasmbin, watscanner;
|
|
|
|
|
|
type
|
|
type
|
|
TParseResult = record
|
|
TParseResult = record
|
|
- error : string;
|
|
|
|
|
|
+ error : string;
|
|
|
|
+ line : integer;
|
|
|
|
+ pos : integer;
|
|
|
|
+ offset : integer;
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
+const
|
|
|
|
+ TokenStr : array[TWatToken] of string = (
|
|
|
|
+ 'uknown', 'end of file', 'error',
|
|
|
|
+ 'index',
|
|
|
|
+ 'string', 'number', '(', ')',
|
|
|
|
+ 'linksymbol',
|
|
|
|
+
|
|
|
|
+ 'instruction',
|
|
|
|
+ 'func',
|
|
|
|
+ 'param', 'result',
|
|
|
|
+ 'module', 'mut', 'funcref',
|
|
|
|
+ 'i32', 'i64',
|
|
|
|
+ 'f32', 'f64',
|
|
|
|
+ 'type',
|
|
|
|
+ 'import', 'global', 'table', 'memory', 'local', 'export',
|
|
|
|
+ 'elem', 'data', 'offset'
|
|
|
|
+ );
|
|
|
|
+
|
|
//function ConsumeToken(sc: TWatScanner; tk: TWatToken): Boolean;
|
|
//function ConsumeToken(sc: TWatScanner; tk: TWatToken): Boolean;
|
|
-function ParseModule(sc: TWatScanner; dst: TWasmModule; var res: TParseResult): Boolean;
|
|
|
|
-procedure ErrorUnexpected(var res: TParseResult; const tokenstr: string = '');
|
|
|
|
-procedure ErrorExpectButFound(var res: TParseResult; const expected: string; const butfound: string = '');
|
|
|
|
-procedure ErrorUnexpectedEof(var res: TParseResult);
|
|
|
|
|
|
+function ParseModule(sc: TWatScanner; dst: TWasmModule; var errMsg: string): Boolean; overload;
|
|
|
|
+function ParseModule(sc: TWatScanner; dst: TWasmModule; out err: TParseResult): Boolean; overload;
|
|
|
|
+
|
|
|
|
+type
|
|
|
|
+ // used to stop the recursive parsing
|
|
|
|
+
|
|
|
|
+ { EParserError }
|
|
|
|
+
|
|
|
|
+ EParserError = class(Exception)
|
|
|
|
+ offset : integer;
|
|
|
|
+ constructor Create(const amsg: string; aofs: integer);
|
|
|
|
+ end;
|
|
|
|
|
|
implementation
|
|
implementation
|
|
|
|
|
|
|
|
+const
|
|
|
|
+ WAT_DEFTYPES='iN or fN';
|
|
|
|
+
|
|
|
|
+procedure ParseError(sc: TWatScanner; const errMsg: string);
|
|
|
|
+begin
|
|
|
|
+ raise EParserError.Create(errMsg, sc.ofs);
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure ErrorUnexpected(sc: TWatScanner; const tokenstr: string = '');
|
|
|
|
+begin
|
|
|
|
+ ParseError(sc, 'unexpected '+tokenstr);
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure ErrorExpectButFound(sc: TWatScanner; const expected: string; const butfound: string =''); overload;
|
|
|
|
+var
|
|
|
|
+ r : string;
|
|
|
|
+begin
|
|
|
|
+ if butfound = '' then r := sc.resText
|
|
|
|
+ else r := butfound;
|
|
|
|
+ ParseError(sc, 'expected "'+expected+'", but "'+r+'" found');
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure ErrorUnexpectedEof(sc: TWatScanner);
|
|
|
|
+begin
|
|
|
|
+ ParseError(sc, 'unexpected end of file');
|
|
|
|
+end;
|
|
|
|
+
|
|
procedure ConsumeAnyOpenToken(sc: TWatScanner; out tk: TWatToken;
|
|
procedure ConsumeAnyOpenToken(sc: TWatScanner; out tk: TWatToken;
|
|
- out hadOpenBrace: Boolean);
|
|
|
|
|
|
+ out hadOpenBrace: Boolean); overload;
|
|
begin
|
|
begin
|
|
sc.Next;
|
|
sc.Next;
|
|
hadOpenBrace := sc.token = weOpenBrace;
|
|
hadOpenBrace := sc.token = weOpenBrace;
|
|
@@ -29,6 +85,15 @@ begin
|
|
tk:=sc.token;
|
|
tk:=sc.token;
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
+
|
|
|
|
+procedure ConsumeAnyOpenToken(sc: TWatScanner; out tk: TWatToken); overload;
|
|
|
|
+var
|
|
|
|
+ op: Boolean;
|
|
|
|
+begin
|
|
|
|
+ ConsumeAnyOpenToken(sc, tk, op);
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+
|
|
function ConsumeOpenToken(sc: TWatScanner; tk: TWatToken): Boolean;
|
|
function ConsumeOpenToken(sc: TWatScanner; tk: TWatToken): Boolean;
|
|
begin
|
|
begin
|
|
sc.Next;
|
|
sc.Next;
|
|
@@ -39,22 +104,22 @@ begin
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
|
|
-function ConsumeToken(sc: TWatScanner; tk: TWatToken; var res: TParseResult): Boolean;
|
|
|
|
|
|
+function ConsumeToken(sc: TWatScanner; tk: TWatToken): Boolean;
|
|
begin
|
|
begin
|
|
Result:=sc.token =tk;
|
|
Result:=sc.token =tk;
|
|
if not Result then
|
|
if not Result then
|
|
- ErrorExpectButFound(res, 'some token','?')
|
|
|
|
|
|
+ ErrorExpectButFound(sc,TokenStr[tk])
|
|
else
|
|
else
|
|
sc.Next;
|
|
sc.Next;
|
|
end;
|
|
end;
|
|
|
|
|
|
-function ParseNumOfId(sc: TWatScanner; out num: integer; out id: string; var res: TParseResult): Boolean;
|
|
|
|
|
|
+function ParseNumOfId(sc: TWatScanner; out num: integer; out id: string): Boolean;
|
|
begin
|
|
begin
|
|
num:=-1;
|
|
num:=-1;
|
|
id:='';
|
|
id:='';
|
|
Result := sc.Next;
|
|
Result := sc.Next;
|
|
if not Result then begin
|
|
if not Result then begin
|
|
- ErrorUnexpectedEof(res);
|
|
|
|
|
|
+ ErrorUnexpectedEof(sc);
|
|
Exit;
|
|
Exit;
|
|
end;
|
|
end;
|
|
|
|
|
|
@@ -62,7 +127,7 @@ begin
|
|
weNumber: num:=sc.GetInt32;
|
|
weNumber: num:=sc.GetInt32;
|
|
weIdent: id:=sc.resText;
|
|
weIdent: id:=sc.resText;
|
|
else
|
|
else
|
|
- ErrorExpectButFound(res, 'index');
|
|
|
|
|
|
+ ErrorExpectButFound(sc, 'index', TokenStr[sc.token]);
|
|
Result := false;
|
|
Result := false;
|
|
end;
|
|
end;
|
|
Result := true;
|
|
Result := true;
|
|
@@ -83,34 +148,31 @@ begin
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
|
|
-function ParseParam(sc: TWatScanner; out id: string; out tp: byte; var res: TParseResult): Boolean;
|
|
|
|
|
|
+procedure ParseParam(sc: TWatScanner; out id: string; out tp: byte; allowIdent: Boolean = true; consumeClose: Boolean = true);
|
|
begin
|
|
begin
|
|
tp:=0;
|
|
tp:=0;
|
|
id:='';
|
|
id:='';
|
|
- if sc.token=weParam then sc.Next;
|
|
|
|
|
|
|
|
- if sc.token=weIdent then begin
|
|
|
|
|
|
+ if allowIdent and (sc.token=weIdent) then begin
|
|
id:=sc.resText;
|
|
id:=sc.resText;
|
|
sc.Next;
|
|
sc.Next;
|
|
end;
|
|
end;
|
|
|
|
|
|
- if not TokenTypeToValType(sc.token, tp) then begin
|
|
|
|
- ErrorExpectButFound(res, 'type');
|
|
|
|
- Result:=false;
|
|
|
|
- Exit;
|
|
|
|
- end else
|
|
|
|
- Result:=true;
|
|
|
|
|
|
+ if not TokenTypeToValType(sc.token, tp) then
|
|
|
|
+ ErrorExpectButFound(sc, WAT_DEFTYPES, TokenStr[sc.token]);
|
|
|
|
+
|
|
sc.Next;
|
|
sc.Next;
|
|
- Result := sc.token=weCloseBrace;
|
|
|
|
- if Result then sc.Next
|
|
|
|
- else ErrorExpectButFound(res, ')');
|
|
|
|
|
|
+
|
|
|
|
+ if consumeClose then
|
|
|
|
+ ConsumeToken(sc, weCloseBrace);
|
|
end;
|
|
end;
|
|
|
|
|
|
-function ParseFunc(sc: TWatScanner; dst: TWasmFunc; var res: TParseResult): Boolean;
|
|
|
|
|
|
+procedure ParseFunc(sc: TWatScanner; dst: TWasmFunc);
|
|
var
|
|
var
|
|
nm : integer;
|
|
nm : integer;
|
|
id : string;
|
|
id : string;
|
|
p : TWasmParam;
|
|
p : TWasmParam;
|
|
|
|
+ tk : TWatToken;
|
|
begin
|
|
begin
|
|
if sc.token=weFunc then sc.Next;
|
|
if sc.token=weFunc then sc.Next;
|
|
repeat
|
|
repeat
|
|
@@ -119,45 +181,51 @@ begin
|
|
sc.Next;
|
|
sc.Next;
|
|
end;
|
|
end;
|
|
|
|
|
|
- Result:=false;
|
|
|
|
- if sc.token=weOpenBrace then begin
|
|
|
|
|
|
+ ConsumeAnyOpenToken(sc, tk);
|
|
|
|
+
|
|
|
|
+ if tk = weType then begin
|
|
|
|
+ if not ParseNumOfId(sc, nm, id) then Exit;
|
|
|
|
+ if nm>=0 then dst.typeIdx:=nm
|
|
|
|
+ else dst.typeId:=id;
|
|
|
|
+ ConsumeAnyOpenToken(sc, tk);
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+ while tk = weParam do begin
|
|
|
|
+ p:=dst.GetInlineType.AddParam;
|
|
sc.Next;
|
|
sc.Next;
|
|
- case sc.token of
|
|
|
|
- weType: begin
|
|
|
|
- if not ParseNumOfId(sc, nm, id, res) then Exit;
|
|
|
|
- if nm>=0 then dst.typeIdx:=nm
|
|
|
|
- else dst.typeId:=id;
|
|
|
|
- end;
|
|
|
|
- weParam: begin
|
|
|
|
- sc.Next;
|
|
|
|
- p:=dst.GetInlineType.AddParam;
|
|
|
|
- if not ParseParam(sc, p.id, p.tp, res) then Exit;
|
|
|
|
- end;
|
|
|
|
- weResult: begin
|
|
|
|
- sc.Next;
|
|
|
|
- p:=dst.GetInlineType.AddResult;
|
|
|
|
- if not ParseParam(sc, p.id, p.tp, res) then Exit;
|
|
|
|
- end;
|
|
|
|
- weLocal: begin
|
|
|
|
- sc.Next;
|
|
|
|
- p:=dst.AddLocal;
|
|
|
|
- if not ParseParam(sc, p.id, p.tp, res) then Exit;
|
|
|
|
- end;
|
|
|
|
- else
|
|
|
|
- ErrorUnexpected(res, 'booh');
|
|
|
|
- Exit;
|
|
|
|
- end;
|
|
|
|
- if not ConsumeToken(sc, weCloseBrace, res) then Exit;
|
|
|
|
|
|
+ ParseParam(sc, p.id, p.tp);
|
|
|
|
+ ConsumeAnyOpenToken(sc, tk);
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+ while tk = weResult do begin
|
|
|
|
+ p:=dst.GetInlineType.AddResult;
|
|
|
|
+ sc.Next;
|
|
|
|
+ ParseParam(sc, p.id, p.tp, false);
|
|
|
|
+ ConsumeAnyOpenToken(sc, tk);
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+ while tk = weLocal do begin
|
|
|
|
+ p:=dst.AddLocal;
|
|
|
|
+ sc.Next;
|
|
|
|
+ ParseParam(sc, p.id, p.tp);
|
|
|
|
+ ConsumeAnyOpenToken(sc, tk);
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+ if not (tk in [weInstr, weCloseBrace]) then
|
|
|
|
+ ErrorExpectButFound(sc, 'identifier');
|
|
|
|
+
|
|
|
|
+ while tk<>weCloseBrace do begin
|
|
|
|
+ ConsumeToken(sc, weInstr);
|
|
end;
|
|
end;
|
|
|
|
|
|
until sc.token=weCloseBrace;
|
|
until sc.token=weCloseBrace;
|
|
sc.Next;
|
|
sc.Next;
|
|
end;
|
|
end;
|
|
|
|
|
|
-function ParseModule(sc: TWatScanner; dst: TWasmModule; var res: TParseResult): Boolean;
|
|
|
|
|
|
+function ParseModuleInt(sc: TWatScanner; dst: TWasmModule): Boolean;
|
|
begin
|
|
begin
|
|
if not ConsumeOpenToken(sc, weModule) then begin
|
|
if not ConsumeOpenToken(sc, weModule) then begin
|
|
- Result := false;
|
|
|
|
|
|
+ ErrorExpectButFound(sc, 'module');
|
|
Exit;
|
|
Exit;
|
|
end;
|
|
end;
|
|
|
|
|
|
@@ -167,12 +235,11 @@ begin
|
|
sc.Next;
|
|
sc.Next;
|
|
|
|
|
|
if sc.token = weFunc then begin
|
|
if sc.token = weFunc then begin
|
|
- Result := ParseFunc(sc, dst.AddFunc, res);
|
|
|
|
- if not Result then Exit;
|
|
|
|
|
|
+ ParseFunc(sc, dst.AddFunc);
|
|
end;
|
|
end;
|
|
|
|
|
|
end else if sc.token<>weCloseBrace then begin
|
|
end else if sc.token<>weCloseBrace then begin
|
|
- ErrorUnexpected(res);
|
|
|
|
|
|
+ ErrorUnexpected(sc, TokenStr[sc.token]);
|
|
Result := false;
|
|
Result := false;
|
|
exit;
|
|
exit;
|
|
end;
|
|
end;
|
|
@@ -181,21 +248,62 @@ begin
|
|
Result := true;
|
|
Result := true;
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure ErrorUnexpected(var res: TParseResult; const tokenstr: string);
|
|
|
|
|
|
+function ParseModule(sc: TWatScanner; dst: TWasmModule; var errMsg: string): Boolean;
|
|
|
|
+var
|
|
|
|
+ res : TParseResult;
|
|
begin
|
|
begin
|
|
- res.error:='unexpected token '+tokenstr;
|
|
|
|
|
|
+ Result := ParseModule(sc, dst, res);
|
|
|
|
+ if not Result then begin
|
|
|
|
+ errMsg:=Format('line: %d, pos: %d, %s', [res.line, res.pos, res.error]);
|
|
|
|
+ end else
|
|
|
|
+ errMsg:='';
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure ErrorUnexpectedEof(var res: TParseResult);
|
|
|
|
|
|
+procedure GetLineAndPos(const buf: string; ofs: integer; out line, pos: integer);
|
|
|
|
+var
|
|
|
|
+ i: integer;
|
|
|
|
+ ll: integer;
|
|
begin
|
|
begin
|
|
- res.error:='unexpected end of file';
|
|
|
|
|
|
+ i:=1;
|
|
|
|
+ line:=1;
|
|
|
|
+ ll:=1;
|
|
|
|
+ while (i<=length(buf)) and (i<ofs) do begin
|
|
|
|
+ if (buf[i]=#13) or (buf[i]=#10) then begin
|
|
|
|
+ inc(line);
|
|
|
|
+ if (i<=length(buf)) and (i<ofs) and ((buf[i]=#13) or (buf[i]=#10)) and (buf[i] <> buf[i-1]) then
|
|
|
|
+ inc(i);
|
|
|
|
+ ll:=i;
|
|
|
|
+ end;
|
|
|
|
+ inc(i);
|
|
|
|
+ end;
|
|
|
|
+ pos:=ofs - ll;
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure ErrorExpectButFound(var res: TParseResult; const expected, butfound: string);
|
|
|
|
|
|
+function ParseModule(sc: TWatScanner; dst: TWasmModule; out err: TParseResult): Boolean;
|
|
|
|
+begin
|
|
|
|
+ try
|
|
|
|
+ err.error:='';
|
|
|
|
+ err.pos:=0;
|
|
|
|
+ err.line:=0;
|
|
|
|
+ err.offset:=0;
|
|
|
|
+ ParseModuleInt(sc, dst);
|
|
|
|
+ Result:=true;
|
|
|
|
+ except
|
|
|
|
+ on x: EParserError do begin
|
|
|
|
+ err.error := x.Message;
|
|
|
|
+ err.offset := x.offset;
|
|
|
|
+ GetLineAndPos(sc.buf, x.offset, err.line, err.pos);
|
|
|
|
+ Result:=false;
|
|
|
|
+ end;
|
|
|
|
+ end;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+{ EParserError }
|
|
|
|
+
|
|
|
|
+constructor EParserError.Create(const amsg: string; aofs: integer);
|
|
begin
|
|
begin
|
|
- res.error:=expected +' is expected';
|
|
|
|
- if butfound<>'' then
|
|
|
|
- res.error:=res.error+', but '+butfound+ ' found';
|
|
|
|
|
|
+ inherited Create(amsg);
|
|
|
|
+ offset:=aofs;
|
|
end;
|
|
end;
|
|
|
|
|
|
end.
|
|
end.
|