pax_javascript.pas

来自「Delphi脚本控件」· PAS 代码 · 共 2,775 行 · 第 1/5 页

PAS
2,775
字号
          begin
            result := true;
            Exit;
          end;
    end;
  end;
end;

procedure TPaxJavaScriptParser.Match(const S: String);
begin
  if (S = ';') and (CurrToken.Text <> S) then
  begin
    Scanner.BuffToken := CurrToken;

    CurrToken.Text := ';';
    CurrToken.ID := SP_SEMICOLON;
    Exit;
  end;

  inherited;
end;

constructor TPaxJavaScriptParser.Create;
begin
  inherited;

  JavaScriptOperators := true;

  Scanner := TPaxJavaScriptScanner.Create(Self);

  UpCase := false;

  NewLine := false;

  LeftSideID := 0;

  with Keywords do
  begin
    Add('base');
    Add('break');
    Add('case');
    Add('catch');
    Add('class');
    Add('continue');
    Add('delete');
    Add('do');
    Add('else');
    Add('false');
    Add('finally');
    Add('for');
    Add('function');
    Add('get');
    Add('goto');
    Add('if');
    Add('in');
    Add('instanceof');

    Add('namespace');
    Add('new');
    Add('out');
    Add('public');
    Add('private');
    Add('reduced');
    Add('ref');
    Add('return');
    Add('set');
    Add('static');
    Add('structure');
    Add('switch');
//    Add('THIS');
    Add('throw');
    Add('true');
    Add('try');
    Add('typeof');
    Add('var');
    Add('void');
    Add('using');
    Add('while');
    Add('with');

    Add('print');
    Add('println');
    Add('property');
  end;
end;

function TPAXJavaScriptParser.Gen(Op, Arg1, Arg2, Res: Integer): Integer;
begin
  Code.RemoveNops;

  if Op = OP_PLUS then
    Op := Op_PLUS_EX
  else if Op = OP_MINUS then
    Op := Op_MINUS_EX
  else if Op = OP_UNARY_MINUS then
    Op := Op_UNARY_MINUS_EX
  else if Op = OP_MULT then
    Op := Op_MULT_EX
  else if Op = OP_DIV then
    Op := Op_DIV_EX
  else if Op = OP_MOD then
    Op := Op_MOD_EX
  else if Op = OP_LEFT_SHIFT then
    Op := Op_LEFT_SHIFT_EX
  else if Op = OP_RIGHT_SHIFT then
    Op := Op_RIGHT_SHIFT_EX
  else if Op = OP_UNSIGNED_RIGHT_SHIFT then
    Op := Op_UNSIGNED_RIGHT_SHIFT_EX
  else if Op = OP_EQ then
    Op := Op_EQ_EX
  else if Op = OP_NE then
    Op := Op_NE_EX
  else if Op = OP_ID then
    Op := Op_ID_EX
  else if Op = OP_NI then
    Op := Op_NI_EX
  else if Op = OP_LT then
    Op := Op_LT_EX
  else if Op = OP_LE then
    Op := Op_LE_EX
  else if Op = OP_GT then
    Op := Op_GT_EX
  else if Op = OP_GE then
    Op := Op_GE_EX;

  result := inherited Gen(Op, Arg1, Arg2, Res);
end;

procedure TPAXJavaScriptParser.Call_SCANNER;
var
  L1, L2: Integer;
begin
  L1 := Scanner.LineNumber;
  inherited;
  L2 := Scanner.LineNumber;
  NewLine := L2 > L1;

  if IsCurrText('null') then
  begin
    CurrToken.ID := UndefinedID;
    CurrToken.TokenClass := tcId;
  end;
end;

destructor TPAXJavaScriptParser.Destroy;
begin
  inherited;
end;

procedure TPaxJavaScriptParser.Reset;
begin
  inherited;
end;

function TPaxJavaScriptParser.Parse_EvalExpression: Integer;
begin
//  result := Parse_LeftHandSideExpression;
  result := Parse_Expression;
end;

function TPaxJavaScriptParser.Parse_ArgumentExpression: Integer;
begin
  result := Parse_AssignmentExpression;
end;

///////  EXPRESSIONS /////////////////////////////////////////////////////////

function TPaxJavaScriptParser.Parse_ArgumentList(SubID: Integer; var Vars: Integer;
                                    CheckCall: Boolean = true;
                                    Erase: Boolean = true): Integer;

procedure _ParseExpr;
var
  TempID, ExprID, K1, K2: Integer;
begin
  Inc(result);
  K1 := Code.Card;
  ExprID := Parse_ArgumentExpression;
  Code.RemoveNops;
  K2 := Code.Card;
  if K2 - K1 > 0 then
  begin
    TempID := NewVar;
    Gen(OP_ASSIGN_SIMPLE, TempID, ExprID, TempID);
    Gen(OP_PUSH, TempID, 0, 0);
  end
  else
    Gen(OP_PUSH, ExprID, 0, 0);
end;

var
  I: Integer;
  S: String;
begin
  Vars := 0;
  result := 0;
  ArgumentListSwitch := true;
  if Erase then
  begin
    S := Name[SubId];
    I := ArrayParamMethods.IndexOf(S);
    if I = -1 then
      ArgumentListSwitch := false;
  end;

  _ParseExpr;
  while IsCurrText(',') do
  begin
    Call_SCANNER;
    _ParseExpr;
  end;

  ArgumentListSwitch := false;
  if Erase then
  begin
    S := Name[SubId];
    I := ArrayParamMethods.IndexOf(S);
    if I = -1 then
      ArrayArgumentList.Clear;
  end;
end;

function TPaxJavaScriptParser.Parse_PrimaryExpression: Integer;
var
  SubID, ID: Integer;
  IsArrayItem: Boolean;
begin
  if IsCurrText('(') then // (Expression)
  begin
    Call_SCANNER;
    result := Parse_Expression;
    Match(')');
    Call_SCANNER;
  end
  else if IsCurrText('base') then // (base access)
  begin
    if CurrClassID = 0 then
      raise TPAXScriptFailure.Create(errStatementIsNotAllowedHere);
    if CurrSubID <> CurrMethodID then
      raise TPAXScriptFailure.Create(errStatementIsNotAllowedHere);

    Call_SCANNER;
    Match('.');
    FieldSwitch := true;
    Call_SCANNER;
    result := Parse_Ident;
    GenRef(CurrThisID, maMyBase, result);
  end
  else if IsCurrText('this') then // (base access)
  begin
    if CurrClassID = 0 then
      raise TPAXScriptFailure.Create(errStatementIsNotAllowedHere);
    if CurrSubID <> CurrMethodID then
      raise TPAXScriptFailure.Create(errStatementIsNotAllowedHere);

    if IsNextText('.') then
    begin
      Call_SCANNER;
      Match('.');
      FieldSwitch := true;
      Call_SCANNER;
      result := Parse_Ident;
      GenRef(CurrThisID, maMyClass, result);
    end
    else
    begin
      result := Parse_Ident;
    end;
  end
  else if IsCurrText('[') then // (array literal)
    result := Parse_ArrayLiteral
  else if IsCurrText('{') then // (object literal)
    result := Parse_ObjectLiteral
  else if IsCurrText('/') then // (regexp literal)
    result := Parse_RegExpr('RegExp')
  else if IsCurrText('&') then
  begin
    result := NewVar;
    Call_SCANNER;
    if IsCallOperator then
      RemoveLastOperator;

    IsArrayItem := IsNextText('[') or IsNextText('(');

    SubID := Parse_MemberExpression(0);
    if IsCallOperator and (not IsArrayItem) then
       RemoveLastOperator;
    Gen(OP_ASSIGN_ADDRESS, result, SubID, result);
  end
  else if IsCurrText('*') then
  begin
    Call_SCANNER;
    ID := Parse_MemberExpression(0);
    result := NewVar;
    Gen(OP_GET_TERMINAL, ID, 0, result);
  end
  else if IsCurrText('true') then
  begin
    result := NewConst(true);
    Call_SCANNER;
  end
  else if IsCurrText('function') then
  begin
    result := Parse_FunctionStmt([]);
    while Kind[result] <> KindTYPE do
      Dec(result);
  end
  else if IsCurrText('false') then
  begin
    result := NewConst(false);
    Call_SCANNER;
  end
  else if IsConstant then
  begin
    result := CurrToken.ID;
    if TypeID[result] = typeSTRING then
    begin
      result := Parse_StringLiteral;
    end
    else
      Call_SCANNER;
  end
  else
  begin
    if IsNextText('.') and IsNext2Text('arguments') then
    begin
      Call_SCANNER;
      Call_SCANNER;
      result := Parse_Ident;
      Exit;
    end;
    result := Parse_Ident;
    result := GenEvalWith(result);
  end;
end;

function TPaxJavaScriptParser.Parse_ArrayLiteral: Integer;
var
  L, K, ArgID: Integer;
begin
  // '['

  K := 0;
  result := NewVar;

  if ArgumentListSwitch then
    ArrayArgumentList.Add(result);


  Gen(OP_PUSH, 0, 0, 0);
  L := LastCodeLine;

  Gen(OP_CREATE_ARRAY, result, 1, 0);

  Call_SCANNER;
  if not IsCurrText(']') then
  begin
    Gen(OP_PUSH, NewConst(K), 0, 0);
    ArgID := Parse_AssignmentExpression;
    Gen(OP_PUSH, ArgID, 0, 0);
    Gen(OP_PUT_PROPERTY, result, 2, 0);

    while IsCurrText(',') do
    begin
      Inc(K);

      Call_SCANNER;
      Gen(OP_PUSH, NewConst(K), 0, 0);
      ArgID := Parse_AssignmentExpression;
      Gen(OP_PUSH, ArgID, 0, 0);
      Gen(OP_PUT_PROPERTY, result, 2, 0);
    end;
  end
  else
    K := -1;

  Code.Prog[L].Arg1 := NewConst(K);

  Match(']');
  Call_SCANNER;
end;

function TPaxJavaScriptParser.Parse_ObjectLiteral: Integer;
var
  RefID, ClassID: Integer;
begin
// Match "{"

  result := NewVar;
  RefID := NewVar;
  ClassID := NewVar;

  Name[ClassID] := 'Object';
  Name[RefID] := 'Object';

  Gen(OP_EVAL_WITH, 0, 0, ClassID);
  Gen(OP_CREATE_OBJECT, ClassID, 0, result);

  GenRef(result, maAny, RefID);
  Gen(OP_CALL, RefID, 0, result);

  Call_SCANNER;

  if not IsCurrText('}') then
  repeat
    Gen(OP_PUSH, CurrToken.ID, 0, 0);

    Call_SCANNER;
    Match(':');

    Call_SCANNER;
    Gen(OP_PUSH, Parse_AssignmentExpression, 0, 0);

    Gen(OP_PUT_PROPERTY, result, 2, 0);

    if IsCurrText(',') then
      Call_SCANNER
    else
      Break;
  until False;

  Match('}');
  Call_SCANNER;
end;

function TPaxJavaScriptParser.Parse_MemberExpression(ID: Integer): Integer;
var
  SubID, RefID, Vars: Integer;
label
  Again;
begin
  if ID = 0 then
    result := Parse_PrimaryExpression
  else
    result := ID;

  while CurrToken.Text[1] in ['(','[','.'] do
    case CurrToken.Text[1] of
      '[':
      begin

        SubID := result;
        result := NewVar;

        Call_SCANNER;
        Gen(OP_CALL, SubID, Parse_ArgumentList(SubID, Vars, true, false), result);
//        Code.Prog[Code.Card].AltArg1 := 1; // get property
        SymbolTable.JSIndex[SubId] := true;

        SetVars(Vars);

        Match(']');

        Call_SCANNER;
      end;
      '.':
      begin
        if IsNextText('arguments') then
        begin
          Call_SCANNER;
          result := CurrToken.ID;
          Gen(OP_EVAL_WITH, 0, 0, result);
          Call_SCANNER;
        end
        else
        begin
          FieldSwitch := true;
          Call_SCANNER;
          RefID := Parse_Ident;
          GenRef(result, maAny, RefID);
          result := RefID;

  //        if not (CurrToken.Text[1] in ['(', '[']) then
  //          Gen(OP_CALL, result, 0, result);
        end;
      end;
      '(':
      begin
        SubID := result;
        result := NewVar;

        Call_SCANNER;
        if IsCurrText(')') then
          Gen(OP_CALL, SubID, 0, result)
        else
        begin
          Gen(OP_CALL, SubID, Parse_ArgumentList(SubID, Vars), result);
          SetVars(Vars);
        end;

        Match(')');

        Call_SCANNER;
      end;
    end;
end;

function TPaxJavaScriptParser.Parse_NewExpression: Integer;
var
  ClassID, ObjectID, RefID, SubID: Integer;
  reg_exp, temp: Boolean;
begin
  temp := false;
  
  if IsCurrText('new') then
  begin
    Call_SCANNER;

    reg_exp := StrEql('RegExp', CurrToken.Text);
    if reg_exp then
    begin
      temp := Backslash;
      Backslash := false;
    end;

    ClassID := Parse_Ident;
    ClassID := GenEvalWith(ClassID);

    while IsCurrText('.') do
    begin
      FieldSwitch := true;
      Call_SCANNER;
      RefID := Parse_Ident;
      GenRef(ClassID, maAny, RefID);
      ClassID := RefID;
    end;

    ObjectID := NewVar;
    Gen(OP_CREATE_OBJECT, ClassID, 0, ObjectID);

    if IsCurrText('(') then
    begin
      result := NewRef;
      Name[result] := Name[ClassID];
      GenRef(ObjectID, maMyClass, result);
      result := Parse_MemberExpression(result);
    end
    else if IsCurrText(';') or NewLine then
    begin
      result := NewRef;
      Name[result] := Name[ClassID];
      GenRef(ObjectID, maMyClass, result);
      SubID := result;
      result := NewVar;
      Gen(OP_CALL, SubID, 0, result);
    end
    else
      result := ObjectID;

    TypeID[result] := ClassID;

    if reg_exp then
    begin
      Backslash := temp;
    end;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?