Ignore:
Timestamp:
Apr 22, 2020, 12:04:22 PM (5 years ago)
Author:
chronos
Message:
  • Added: Support for custom functions.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • branches/interpreter2/UParser.pas

    r211 r212  
    2020    function ParseCommand(Block: TBlock; out Command: TCommand): Boolean;
    2121    function ParseProgram(SystemBlock: TBlock; out Prog: TProgram): Boolean;
    22     function ParseBlock(ParentBlock: TBlock; out Block: TBlock): Boolean;
     22    function ParseBlock(ParentBlock: TBlock; out Block: TBlock; ExistingBlock: TBlock = nil): Boolean;
    2323    function ParseBlockVar(Block: TBlock): Boolean;
    2424    function ParseBlockConst(Block: TBlock): Boolean;
     25    function ParseFunction(Block: TBlock; out Func: TFunction): Boolean;
     26    function ParseFunctionParameter(Block: TBlock; out Parameter: TFunctionParameter): Boolean;
    2527    function ParseAssignment(Block: TBlock; out Assignment: TAssignment): Boolean;
    2628    function ParseExpression(Block: TBlock; out Expression: TExpression): Boolean;
     
    194196end;
    195197
    196 function TParser.ParseBlock(ParentBlock: TBlock; out Block: TBlock): Boolean;
     198function TParser.ParseBlock(ParentBlock: TBlock; out Block: TBlock; ExistingBlock: TBlock = nil): Boolean;
    197199var
    198200  BeginEnd: TBeginEnd;
    199 begin
    200   Result := False;
    201   Block := TBlock.Create;
     201  Func: TFunction;
     202begin
     203  Result := False;
     204  if Assigned(ExistingBlock) then Block := ExistingBlock
     205    else Block := TBlock.Create;
    202206  Block.ParentBlock := ParentBlock;
    203   ParseBlockVar(Block);
    204   ParseBlockConst(Block);
     207  while True do begin
     208    if ParseBlockVar(Block) then begin
     209    end else
     210    if ParseBlockConst(Block) then begin
     211    end else
     212    if ParseFunction(Block, Func) then begin
     213      Block.Functions.Add(Func);
     214    end else begin
     215      Break;
     216    end;
     217  end;
    205218  if ParseBeginEnd(Block, BeginEnd) then begin
    206219    Result := True;
     
    208221    Block.BeginEnd := BeginEnd;
    209222    BeginEnd.Parent := Block;
    210   end else Block.Free;
     223  end else begin
     224    if not Assigned(ExistingBlock) then Block.Free;
     225    Block := nil;
     226  end;
    211227end;
    212228
     
    291307end;
    292308
     309function TParser.ParseFunction(Block: TBlock; out Func: TFunction): Boolean;
     310var
     311  Token: TToken;
     312  FunctionParameter: TFunctionParameter;
     313  NewBlock: TBlock;
     314  TypeRef: TType;
     315  Variable: TVariable;
     316  I: Integer;
     317begin
     318  Result := False;
     319  if Tokenizer.CheckNext('function', tkKeyword) then begin
     320    Tokenizer.Expect('function', tkKeyword);
     321    Result := True;
     322    Func := TFunction.Create;
     323    Token := Tokenizer.GetNext;
     324    if Token.Kind = tkIdentifier then begin
     325      Func.Name := Token.Text;
     326      if Tokenizer.CheckNext('(', tkSpecialSymbol) then begin
     327        Tokenizer.Expect('(', tkSpecialSymbol);
     328        while not Tokenizer.CheckNext(')', tkSpecialSymbol) do begin
     329          if Func.Params.Count > 0 then Tokenizer.Expect(',', tkSpecialSymbol);
     330          if ParseFunctionParameter(Block, FunctionParameter) then begin
     331            Func.Params.Add(FunctionParameter);
     332          end else Error('Expected function parameter.');
     333        end;
     334        Tokenizer.Expect(')', tkSpecialSymbol);
     335        for I := 0 to Func.Params.Count - 1 do begin
     336          Variable := TVariable.Create;
     337          Variable.Name := TFunctionParameter(Func.Params[I]).Name;
     338          Variable.TypeRef := TFunctionParameter(Func.Params[I]).TypeRef;
     339          Variable.Internal := True;
     340          Func.Block.Variables.Add(Variable);
     341        end;
     342      end;
     343      if Tokenizer.CheckNext(':', tkSpecialSymbol) then begin
     344        Tokenizer.Expect(':', tkSpecialSymbol);
     345        Token := Tokenizer.GetNext;
     346        if Token.Kind = tkIdentifier then begin
     347          TypeRef := Block.GetType(Token.Text);
     348          if Assigned(TypeRef) then begin
     349            Func.ResultType := TypeRef;
     350            Variable := TVariable.Create;
     351            Variable.Name := 'Result';
     352            Variable.TypeRef := TypeRef;
     353            Variable.Internal := True;
     354            Func.Block.Variables.Add(Variable);
     355          end else Error('Type ' + Token.Text + ' not found');
     356        end;
     357      end;
     358      Tokenizer.Expect(';', tkSpecialSymbol);
     359      if ParseBlock(Block, NewBlock, Func.Block) then begin
     360        Tokenizer.Expect(';', tkSpecialSymbol);
     361      end else Error('Expected function block');
     362    end else Error('Expected function name');
     363  end;
     364end;
     365
     366function TParser.ParseFunctionParameter(Block: TBlock; out Parameter: TFunctionParameter
     367  ): Boolean;
     368var
     369  Token: TToken;
     370  TypeRef: TType;
     371begin
     372  Result := True;
     373  Token := Tokenizer.GetNext;
     374  if Token.Kind = tkIdentifier then begin
     375    Parameter := TFunctionParameter.Create;
     376    Parameter.Name := Token.Text;
     377    Tokenizer.Expect(':', tkSpecialSymbol);
     378    Token := Tokenizer.GetNext;
     379    if Token.Kind = tkIdentifier then begin
     380      TypeRef := Block.GetType(Token.Text);
     381      if Assigned(TypeRef) then begin
     382        Parameter.TypeRef := TypeRef;
     383      end else Error('Type ' + Token.Text + ' not found');
     384    end else Error('Expected parameter type');
     385  end else Error('Expected parameter name');
     386end;
     387
    293388function TParser.ParseAssignment(Block: TBlock; out Assignment: TAssignment): Boolean;
    294389var
     
    315410        end else begin
    316411          Result := False;
    317           Error('Assignment type mismatch.');
     412          Error('Assignment type mismatch. Expected ' + Variable.TypeRef.Name + ' but got ' + Expression.GetType.Name);
    318413        end;
    319414      end;
     
    348443  Expression: TExpression;
    349444  LastPos: TTokenizerPos;
     445  I: Integer;
     446  ExpectedType: TType;
    350447begin
    351448  Result := False;
     
    362459      else if Token.Text = '<>' then ExpressionOperation.Operation := eoNotEqual
    363460      else Error('Unsupported operator ' + Token.Text);
     461      ExpressionOperation.FunctionRef := ExpressionOperation.TypeRef.Functions.SearchByName(ExpressionOperation.GetFunctionName);
     462      if not Assigned(ExpressionOperation.FunctionRef.ResultType) then
     463        raise Exception.Create('Missing result type for function');
     464      ExpressionOperation.TypeRef := ExpressionOperation.FunctionRef.ResultType;
    364465      ExpressionOperation.Items.Add(Operand);
     466      I := 1;
    365467      if ParseExpression(Block, Expression) then begin
    366         if Expression.GetType = Operand.GetType then
     468        ExpectedType := TFunctionParameter(ExpressionOperation.FunctionRef.Params[I]).TypeRef;
     469        if Expression.GetType = ExpectedType then
    367470          ExpressionOperation.Items.Add(Expression)
    368           else Error('Expression operands needs to be same type.');
     471          else Error('Expression operands needs to be same type. Expected ' + ExpectedType.Name + ' but found ' + Expression.GetType.Name);
    369472      end else Error('Missing operand.');
    370473    end else Operand.Free;
Note: See TracChangeset for help on using the changeset viewer.