Browse Source

* Fix from Mattias Gaertner to implement calling functions without arguments.

git-svn-id: trunk@35166 -
michael 8 years ago
parent
commit
b08297a667

+ 3 - 1
packages/fcl-js/src/jsparser.pp

@@ -153,7 +153,7 @@ Resourcestring
   SErrCatchFinallyExpected   = 'Unexpected token: Expected ''catch'' or ''finally''';
   SErrArgumentsExpected      = 'Unexpected token: Expected '','' or '')'', got %s';
   SErrArrayEnd               = 'Unexpected token: Expected '','' or '']'', got %s';
-  SErrObjectEnd              = 'Unexpected token: Expected '','' or ''}'', got %s';
+  //SErrObjectEnd              = 'Unexpected token: Expected '','' or ''}'', got %s';
   SErrObjectElement          = 'Unexpected token: Expected string, identifier or number after '','' got: %s';
   SErrLiteralExpected        = 'Unexpected token: Expected: null, true, false, number, string, or regex, got: %s';
   SErrInvalidnumber          = 'Invalid numerical value: %s';
@@ -188,6 +188,7 @@ begin
     FCurrent:=FScanner.FetchToken;
     FCurrentString:=FScanner.CurTokenString;
     end;
+  Result:=FCurrent;
   {$ifdef debugparser}Writeln('GetNextToken (',FScanner.CurLine,',',FScanner.CurColumn,'): ',GetEnumName(TypeInfo(TJSToken),Ord(FCurrent)), ' As string: ',FCurrentString);{$endif debugparser}
 end;
 
@@ -1816,6 +1817,7 @@ begin
         end
       else
         n:='';
+      if n='' then ; // what to do with that?
       Consume(tjsBraceOpen);
       F.AFunction:= TJSFuncDef.Create;
       Args:=ParseFormalParameterList;

+ 2 - 9
packages/fcl-js/src/jsscanner.pp

@@ -79,7 +79,6 @@ Type
     FCurToken: TJSToken;
     FCurTokenString: string;
     FCurLine: string;
-    FDefines: TStrings;
     TokenStr: PChar;
     FWasEndOfLine : Boolean;
     FSourceStream : TStream;
@@ -377,7 +376,7 @@ function TJSScanner.DoStringLiteral: TJSToken;
 Var
   Delim : Char;
   TokenStart : PChar;
-  Len,OLen,I : Integer;
+  Len,OLen: Integer;
   S : String;
 
 begin
@@ -522,12 +521,6 @@ end;
 
 Function TJSScanner.FetchToken: TJSToken;
 
-
-var
-  TokenStart, CurPos: PChar;
-  i: TJSToken;
-  OldLength, SectionLength, NestingLevel, Index: Integer;
-
 begin
   if not (FCurtoken in [tjsWhiteSpace,tjsComment]) then
     FWasEndOfLine:=False;
@@ -541,7 +534,7 @@ begin
         exit;
         end;
       end;
-    CurPos:=TokenStr;
+    //CurPos:=TokenStr;
     FCurTokenString := '';
     case TokenStr[0] of
       #0:         // Empty line

+ 32 - 24
packages/fcl-js/src/jswriter.pp

@@ -144,7 +144,7 @@ Type
     Procedure WriteFunctionBody(El: TJSFunctionBody);virtual;
     Procedure WriteFunctionDeclarationStatement(El: TJSFunctionDeclarationStatement);virtual;
     Procedure WriteLabeledStatement(El: TJSLabeledStatement);virtual;
-    Procedure WriteReturnStatement(EL: TJSReturnStatement);virtual;
+    Procedure WriteReturnStatement(El: TJSReturnStatement);virtual;
     Procedure WriteTargetStatement(El: TJSTargetStatement);virtual;
     Procedure WriteFuncDef(FD: TJSFuncDef);virtual;
     Procedure WritePrimaryExpression(El: TJSPrimaryExpression);virtual;
@@ -222,6 +222,7 @@ Var
 
 begin
   Result:=Length(S)*SizeOf(Char);
+  if Result=0 then exit;
   MinLen:=Result+FBufPos;
   If (MinLen>Capacity) then
     begin
@@ -241,6 +242,7 @@ Var
 
 begin
   Result:=Length(S)*SizeOf(UnicodeChar);
+  if Result=0 then exit;
   MinLen:=Result+FBufPos;
   If (MinLen>Capacity) then
     begin
@@ -563,45 +565,46 @@ end;
 
 procedure TJSWriter.WriteArrayLiteral(El: TJSArrayLiteral);
 
-
-
 Var
   Chars : Array[Boolean] of string[2] = ('[]','()');
 
 Var
   i,C : Integer;
-  isArgs,WC : Boolean;
+  isArgs,WC , MultiLine: Boolean;
   BC : String[2];
 
 begin
-  isArgs:=el is TJSArguments;
+  isArgs:=El is TJSArguments;
   BC:=Chars[isArgs];
-  C:=EL.Elements.Count-1;
+  C:=El.Elements.Count-1;
   if C=-1 then
     begin
-    if isArgs then
-      Write(bc)
-    else
-      Write(bc);
+    Write(bc);
     Exit;
     end;
   WC:=(woCompact in Options) or
       ((Not isArgs) and (woCompactArrayLiterals in Options)) or
       (isArgs and (woCompactArguments in Options)) ;
-  if WC then
-    Write(Copy(BC,1,1))
-  else
+  MultiLine:=(not WC) and (C>4);
+  if MultiLine then
     begin
     Writeln(Copy(BC,1,1));
     Indent;
-    end;
+    end
+  else
+    Write(Copy(BC,1,1));
   For I:=0 to C do
-   begin
-   WriteJS(EL.Elements[i].Expr);
-   if I<C then
-     if WC then Write(', ') else Writeln(',')
-   end;
-  if not WC then
+    begin
+    WriteJS(El.Elements[i].Expr);
+    if I<C then
+      if WC then
+        Write(',')
+      else if MultiLine then
+        Writeln(',')
+      else
+        Write(', ');
+    end;
+  if MultiLine then
     begin
     Writeln('');
     Undent;
@@ -685,7 +688,7 @@ procedure TJSWriter.WriteCallExpression(El: TJSCallExpression);
 begin
   WriteJS(El.Expr);
   if Assigned(El.Args) then
-    WriteArrayLiteral(EL.Args)
+    WriteArrayLiteral(El.Args)
   else
     Write('()');
 end;
@@ -1009,11 +1012,16 @@ begin
     Error('Unknown target statement class: "%s"',[EL.ClassName])
 end;
 
-procedure TJSWriter.WriteReturnStatement(EL: TJSReturnStatement);
+procedure TJSWriter.WriteReturnStatement(El: TJSReturnStatement);
 
 begin
-  Write('return ');
-  WriteJS(EL.Expr);
+  if El.Expr=nil then
+    Write('return')
+  else
+    begin
+    Write('return ');
+    WriteJS(El.Expr);
+    end;
 end;
 
 procedure TJSWriter.WriteLabeledStatement(El: TJSLabeledStatement);

+ 1 - 13
packages/fcl-js/tests/tcparser.pp

@@ -5,7 +5,7 @@ unit tcparser;
 interface
 
 uses
-  Classes, SysUtils, fpcunit, testutils, testregistry, jsParser, jstree, jsbase;
+  Classes, SysUtils, fpcunit, testregistry, jsParser, jstree, jsbase;
 
 type
 
@@ -172,9 +172,6 @@ Function TTestJSParser.GetFirstStatement: TJSElement;
 
 Var
   E : TJSElementNodes;
-  N : TJSElement;
-  X : TJSExpressionStatement;
-
 begin
   E:=GetStatements;
   AssertNotNull('Have statements',E);
@@ -186,8 +183,6 @@ end;
 Function TTestJSParser.GetFirstVar: TJSElement;
 Var
   E : TJSElementNodes;
-  N : TJSElement;
-  X : TJSExpressionStatement;
 begin
   E:=GetVars;
   AssertNotNull('Have statements',E);
@@ -202,8 +197,6 @@ Function TTestJSParser.GetExpressionStatement: TJSExpressionStatement;
 
 Var
   N : TJSElement;
-  X : TJSExpressionStatement;
-
 begin
   N:=GetFirstStatement;
   CheckClass(N,TJSExpressionStatement);
@@ -2247,8 +2240,6 @@ procedure TTestJSParser.TestSwitchEmpty;
 Var
   E : TJSElement;
   S : TJSSwitchStatement;
-  P : TJSPrimaryExpressionIdent;
-
 begin
   CreateParser('switch (a) {}');
   E:=GetFirstStatement;
@@ -2265,7 +2256,6 @@ procedure TTestJSParser.TestSwitchOne;
 Var
   E : TJSElement;
   S : TJSSwitchStatement;
-  P : TJSPrimaryExpressionIdent;
   C : TJSCaseElement;
 begin
   CreateParser('switch (a) { case c : {}}');
@@ -2286,7 +2276,6 @@ procedure TTestJSParser.TestSwitchTwo;
 Var
   E : TJSElement;
   S : TJSSwitchStatement;
-  P : TJSPrimaryExpressionIdent;
   C : TJSCaseElement;
 begin
   CreateParser('switch (a) { case c: {}'+sLineBreak+' case d: {}}');
@@ -2310,7 +2299,6 @@ procedure TTestJSParser.TestSwitchTwoDefault;
 Var
   E : TJSElement;
   S : TJSSwitchStatement;
-  P : TJSPrimaryExpressionIdent;
   C : TJSCaseElement;
 begin
   CreateParser('switch (a) { case c: {} case d: {} default: {}}');

+ 1 - 3
packages/fcl-js/tests/tcscanner.pp

@@ -5,7 +5,7 @@ unit tcscanner;
 interface
 
 uses
-  Classes, SysUtils, Typinfo, fpcunit, testutils, testregistry, jstoken, jsscanner;
+  Classes, SysUtils, Typinfo, fpcunit, testregistry, jstoken, jsscanner;
 
 type
 
@@ -190,7 +190,6 @@ end;
 procedure TTestJSScanner.AssertEquals(AMessage : String; AExpected, AActual: TJSToken);
 
 Var
-  J : TJSToken;
   S,EN1,EN2 : String;
 
 begin
@@ -857,7 +856,6 @@ procedure TTestJSScanner.DoTestString(S: String);
 
 Var
   J : TJSToken;
-  T : String;
 begin
   CreateScanner(S);
   try

+ 0 - 1
packages/fcl-js/tests/tcwriter.pp

@@ -2430,7 +2430,6 @@ end;
 
 
 Initialization
-
   RegisterTests([TTestTestJSWriter,TTestLiteralWriter,TTestExpressionWriter,TTestStatementWriter]);
 end.
 

+ 52 - 11
packages/fcl-passrc/src/pasresolver.pp

@@ -276,6 +276,7 @@ type
     btVariant,     // variant
     btNil,         // nil = pointer, class, procedure, method, ...
     btProc,        // TPasProcedure
+    btBuiltInProc,
     btSet,
     btRange
     );
@@ -363,7 +364,8 @@ const
     'Text',
     'Variant',
     'Nil',
-    'PasProcedure',
+    'Procedure/Function',
+    'BuiltInProc',
     '[set]',
     '..range..'
     );
@@ -707,8 +709,9 @@ type
   end;
 
   TResolvedReferenceFlag = (
-    rrfVMT, // use VMT for call
-    rrfNewInstance // constructor call
+    rrfCallWithoutParams, // a TPrimitiveExpr is a call without params
+    rrfNewInstance, // constructor call (without it call a constructor as normal method)
+    rrfVMT // use VMT for call
     );
   TResolvedReferenceFlags = set of TResolvedReferenceFlag;
 
@@ -872,6 +875,7 @@ type
     procedure ResolveImplForLoop(Loop: TPasImplForLoop);
     procedure ResolveImplWithDo(El: TPasImplWithDo);
     procedure ResolveImplAssign(El: TPasImplAssign);
+    procedure ResolveImplSimple(El: TPasImplSimple);
     procedure ResolveImplRaise(El: TPasImplRaise);
     procedure ResolveExpr(El: TPasExpr);
     procedure ResolveBooleanExpr(El: TPasExpr);
@@ -2058,7 +2062,7 @@ begin
   Item:=FindLocalIdentifier(aName);
   while Item<>nil do
     begin
-    writeln('TPasIdentifierScope.IterateElements ',ClassName,' ',Item.Identifier,' ',GetObjName(Item.Element));
+    //writeln('TPasIdentifierScope.IterateElements ',ClassName,' ',Item.Identifier,' ',GetObjName(Item.Element));
     {$IFDEF VerbosePasResolver}
     OldElement:=Item.Element;
     {$ENDIF}
@@ -3391,7 +3395,7 @@ begin
   else if El.ClassType=TPasImplAssign then
     ResolveImplAssign(TPasImplAssign(El))
   else if El.ClassType=TPasImplSimple then
-    ResolveExpr(TPasImplSimple(El).expr)
+    ResolveImplSimple(TPasImplSimple(El))
   else if El.ClassType=TPasImplBlock then
     ResolveImplBlock(TPasImplBlock(El))
   else if El.ClassType=TPasImplRepeatUntil then
@@ -3591,7 +3595,10 @@ begin
   ComputeElement(El.right,RightResolved,[rcSkipTypeAlias]);
 
   if RightResolved.BaseType=btProc then
+    begin
+    // ToDo: Delphi also uses left side to decide whether use function reference or function result
     ComputeProcWithoutParams(RightResolved,El.right);
+    end;
 
   case El.Kind of
   akDefault:
@@ -3642,6 +3649,14 @@ begin
   end;
 end;
 
+procedure TPasResolver.ResolveImplSimple(El: TPasImplSimple);
+var
+  ExprResolved: TPasResolverResult;
+begin
+  ResolveExpr(El.expr);
+  ComputeElement(El.expr,ExprResolved,[rcSkipTypeAlias,rcReturnFuncResult]);
+end;
+
 procedure TPasResolver.ResolveImplRaise(El: TPasImplRaise);
 var
   ResolvedEl: TPasResolverResult;
@@ -3717,14 +3732,15 @@ begin
   DeclEl:=FindElementWithoutParams(aName,FindData,El,false);
   if DeclEl is TPasProcedure then
     begin
-    // identifier is a call and args brackets are missing
+    // identifier is a proc and args brackets are missing
     if El.Parent.ClassType=TPasProperty then
       // a property accessor does not need args -> ok
     else
       begin
+      // examples: funca or @proca or a.funca or @a.funca ...
       Proc:=TPasProcedure(DeclEl);
       if (Proc.ProcType.Args.Count>0)
-          and (TPasArgument(Proc.ProcType.Args[0]).ValueExpr=nil)
+          and (TPasArgument(Proc.ProcType.Args[0]).ValueExpr=nil) // no default value -> param needed
           and not ExprIsAddrTarget(El)
       then
         RaiseMsg(nWrongNumberOfParametersForCallTo,
@@ -4608,10 +4624,19 @@ procedure TPasResolver.ComputeBinaryExpr(Bin: TBinaryExpr; out
 var
   LeftResolved, RightResolved: TPasResolverResult;
 begin
+  if (Bin.OpCode=eopSubIdent)
+  or ((Bin.OpCode=eopNone) and (Bin.left is TInheritedExpr)) then
+    begin
+    ComputeElement(Bin.right,ResolvedEl,Flags);
+    exit;
+    end;
+
   ComputeElement(Bin.left,LeftResolved,Flags);
   ComputeElement(Bin.right,RightResolved,Flags);
   // ToDo: check operator overloading
 
+  //writeln('TPasResolver.ComputeBinaryExpr ',OpcodeStrings[Bin.OpCode],' Left=',GetResolverResultDesc(LeftResolved),' Right=',GetResolverResultDesc(RightResolved));
+
   if LeftResolved.BaseType=btProc then
     ComputeProcWithoutParams(LeftResolved,Bin.left);
   if RightResolved.BaseType=btProc then
@@ -5185,7 +5210,7 @@ var
   Proc: TPasProcedure;
 begin
   if ExprIsAddrTarget(Expr) then exit;
-  // call without arguments
+
   if ResolvedEl.IdentEl=nil then
     RaiseNotYetImplemented(20160928183455,Expr,GetResolverResultDesc(ResolvedEl));
   if not (ResolvedEl.IdentEl is TPasProcedure) then
@@ -5195,6 +5220,9 @@ begin
       and (TPasArgument(Proc.ProcType.Args[0]).ValueExpr=nil) then
     RaiseMsg(nWrongNumberOfParametersForCallTo,sWrongNumberOfParametersForCallTo,
       [GetProcDesc(Proc.ProcType)],Expr);
+
+  if Expr.CustomData is TResolvedReference then
+    Include(TResolvedReference(Expr.CustomData).Flags,rrfCallWithoutParams);
   if (ResolvedEl.IdentEl is TPasFunction) then
     ComputeElement(TPasFunction(ResolvedEl.IdentEl).FuncType.ResultEl,ResolvedEl,[])
   else if ResolvedEl.IdentEl.ClassType=TPasConstructor then
@@ -5203,7 +5231,7 @@ begin
     SetResolverValueExpr(ResolvedEl,btContext,aClass,Expr,[rrfReadable]);
     end
   else
-    RaiseXExpectedButYFound('function',ResolvedEl.IdentEl.ElementTypeName,Expr);
+    ; // simple procedure call -> keep ResolvedEl as btProc
 end;
 
 procedure TPasResolver.CheckIsClass(El: TPasElement;
@@ -7582,6 +7610,7 @@ begin
           begin
           if rcConstant in Flags then
             RaiseConstantExprExp(El);
+          Include(TResolvedReference(El.CustomData).Flags,rrfCallWithoutParams);
           if ResolvedEl.IdentEl is TPasFunction then
             // function => return result
             ComputeElement(TPasFunction(ResolvedEl.IdentEl).FuncType.ResultEl,ResolvedEl,Flags-[rcReturnFuncResult])
@@ -7624,7 +7653,7 @@ begin
       SetResolverIdentifier(ResolvedEl,TResElDataBaseType(El.CustomData).BaseType,
         El,TPasUnresolvedSymbolRef(El),[])
     else if El.CustomData is TResElDataBuiltInProc then
-      RaiseInternalError(20161003174747) // should have been computed in El.ClassType=TParamsExpr
+      SetResolverIdentifier(ResolvedEl,btBuiltInProc,El,TPasUnresolvedSymbolRef(El),[])
     else
       RaiseNotYetImplemented(20160926194756,El);
     end
@@ -7810,6 +7839,18 @@ begin
     SetResolverIdentifier(ResolvedEl,btContext,El,TPasProcedureType(El),[])
   else if El.ClassType=TPasArrayType then
     SetResolverIdentifier(ResolvedEl,btContext,El,TPasArrayType(El),[])
+  else if El.ClassType=TInheritedExpr then
+    begin
+    if El.CustomData is TResolvedReference then
+      begin
+        DeclEl:=TResolvedReference(El.CustomData).Declaration as TPasProcedure;
+        SetResolverIdentifier(ResolvedEl,btProc,DeclEl,
+          TPasProcedure(DeclEl).ProcType,[]);
+      end
+    else
+      // no ancestor proc
+      SetResolverIdentifier(ResolvedEl,btBuiltInProc,nil,nil,[]);
+    end
   else
     RaiseNotYetImplemented(20160922163705,El);
 end;
@@ -7855,7 +7896,7 @@ begin
 end;
 
 function TPasResolver.ExprIsAddrTarget(El: TPasExpr): boolean;
-// returns true of El is the last element of an @ operator expression
+// returns true if El is the last element of an @ operator expression
 // e.g. the OnClick in '@p().o[].OnClick'
 //  or '@s[]'
 var

+ 1 - 1
packages/fcl-passrc/src/pastree.pp

@@ -622,7 +622,7 @@ type
   public
     Access: TArgumentAccess;
     ArgType: TPasType;
-    ValueExpr: TPasExpr;
+    ValueExpr: TPasExpr; // the default value
     Function Value : String;
   end;
 

+ 1 - 4
packages/fcl-passrc/tests/tcresolver.pas

@@ -2762,7 +2762,7 @@ begin
   Add('var {#i}i: longint;');
   Add('begin');
   Add('  {@i}i:={@P}P();');
-  CheckResolverException('function expected, but procedure found',PasResolver.nXExpectedButYFound);
+  CheckResolverException('{Incompatible types: got "Procedure/Function" expected "Longint"',PasResolver.nIncompatibleTypesGotExpected);
 end;
 
 procedure TTestResolver.TestFunctionResultInCondition;
@@ -4769,9 +4769,6 @@ begin
   Add('  ff:=@GetNumberFunc;');
   Add('  ff:=GetNumberFuncFunc; // not in Delphi');
   Add('  ff:=GetNumberFuncFunc();');
-  Add('  // forbidden: f:=GetNumberFuncFunc;');
-  Add('  // forbidden: f:=GetNumberFuncFunc();');
-  Add('  // fpc crash: f:=GetNumberFuncFunc()();');
   ParseProgram;
 end;
 

+ 365 - 2
packages/pastojs/tests/tcmodules.pas

@@ -149,15 +149,31 @@ type
     Procedure TestAliasTypeRef;
 
     // functions
+    Procedure TestProcOneParam;
+    Procedure TestFunctionWithoutParams;
+    Procedure TestProcedureWithoutParams;
     Procedure TestPrgProcVar;
     Procedure TestProcTwoArgs;
     Procedure TestUnitProcVar;
+    Procedure TestFunctionResult;
+    // ToDo: overloads
+    Procedure TestNestedProc;
+    Procedure TestForwardProc;
+    Procedure TestNestedForwardProc;
+    Procedure TestAssignFunctionResult;
+    Procedure TestFunctionResultInCondition;
+    Procedure TestExit;
+
+    // ToDo: pass by reference
+
+    // ToDo: procedure type
 
     // ToDo: enums
 
     // statements
     Procedure TestIncDec;
     Procedure TestAssignments;
+    Procedure TestOperators1;
     Procedure TestFunctionInt;
     Procedure TestFunctionString;
     Procedure TestVarRecord;
@@ -166,11 +182,27 @@ type
     Procedure TestRepeatUntil;
     Procedure TestAsmBlock;
     Procedure TestTryFinally;
+    // ToDo: try..except
     Procedure TestCaseOf;
     Procedure TestCaseOf_UseSwitch;
     Procedure TestCaseOfNoElse;
     Procedure TestCaseOfNoElse_UseSwitch;
     Procedure TestCaseOfRange;
+
+    // classes
+    // ToDo: var
+    // ToDo: inheritance
+    // ToDo: constructor
+    // ToDo: second constructor
+    // ToDo: call another constructor within a constructor
+    // ToDo: newinstance
+    // ToDo: BeforeDestruction
+    // ToDo: AfterConstruction
+    // ToDo: event
+
+    // ToDo: class of
+
+    // ToDo: arrays
   end;
 
 function LinesToStr(Args: array of const): string;
@@ -905,6 +937,75 @@ begin
     ]));
 end;
 
+procedure TTestModule.TestProcOneParam;
+begin
+  StartProgram(false);
+  Add('procedure ProcA(i: longint);');
+  Add('begin');
+  Add('end;');
+  Add('begin');
+  Add('  ProcA(3);');
+  ConvertProgram;
+  CheckSource('TestProcOneParam',
+    LinesToStr([ // statements
+    'this.proca = function (i) {',
+    '};'
+    ]),
+    LinesToStr([ // this.$main
+    'this.proca(3);'
+    ]));
+end;
+
+procedure TTestModule.TestFunctionWithoutParams;
+begin
+  StartProgram(false);
+  Add('function FuncA: longint;');
+  Add('begin');
+  Add('end;');
+  Add('var i: longint;');
+  Add('begin');
+  Add('  i:=FuncA();');
+  Add('  i:=FuncA;');
+  Add('  FuncA();');
+  Add('  FuncA;');
+  ConvertProgram;
+  CheckSource('TestProcWithoutParams',
+    LinesToStr([ // statements
+    'this.funca = function () {',
+    '  var result = 0;',
+    '  return result;',
+    '};',
+    'this.i=0;'
+    ]),
+    LinesToStr([ // this.$main
+    'this.i=this.funca();',
+    'this.i=this.funca();',
+    'this.funca();',
+    'this.funca();'
+    ]));
+end;
+
+procedure TTestModule.TestProcedureWithoutParams;
+begin
+  StartProgram(false);
+  Add('procedure ProcA;');
+  Add('begin');
+  Add('end;');
+  Add('begin');
+  Add('  ProcA();');
+  Add('  ProcA;');
+  ConvertProgram;
+  CheckSource('TestProcWithoutParams',
+    LinesToStr([ // statements
+    'this.proca = function () {',
+    '};'
+    ]),
+    LinesToStr([ // this.$main
+    'this.proca();',
+    'this.proca();'
+    ]));
+end;
+
 procedure TTestModule.TestIncDec;
 begin
   StartProgram(false);
@@ -952,6 +1053,37 @@ begin
     ]));
 end;
 
+procedure TTestModule.TestOperators1;
+begin
+  StartProgram(false);
+  Add('var');
+  Add('  v1,v2,v3:longint;');
+  Add('begin');
+  Add('  v1:=1;');
+  Add('  v2:=v1+v1;');
+  Add('  v2:=v1+v1*v2+v1 div v2;');
+  Add('  v3:=-v1;');
+  Add('  v1:=v1-v2;');
+  Add('  v2:=v1;');
+  Add('  if v1<v2 then v3:=v1 else v3:=v2;');
+  ConvertProgram;
+  CheckSource('TestOperators1',
+    LinesToStr([ // statements
+    'this.v1 = 0;',
+    'this.v2 = 0;',
+    'this.v3 = 0;'
+    ]),
+    LinesToStr([ // this.$main
+    'this.v1 = 1;',
+    'this.v2 = (this.v1 + this.v1);',
+    'this.v2 = ((this.v1 + (this.v1 * this.v2)) + (this.v1 / this.v2));',
+    'this.v3 = -this.v1;',
+    'this.v1 = (this.v1 - this.v2);',
+    'this.v2 = this.v1;',
+    'if ((this.v1 < this.v2)) this.v3 = this.v1 else this.v3 = this.v2;'
+    ]));
+end;
+
 procedure TTestModule.TestPrgProcVar;
 begin
   StartProgram(false);
@@ -1006,6 +1138,237 @@ begin
     );
 end;
 
+procedure TTestModule.TestFunctionResult;
+begin
+  StartProgram(false);
+  Add('function Func1: longint;');
+  Add('begin');
+  Add('  Result:=3;');
+  Add('end;');
+  Add('begin');
+  ConvertProgram;
+  CheckSource('TestFunctionResult',
+    LinesToStr([ // statements
+    'this.func1 = function () {',
+    '  var result = 0;',
+    '  result = 3;',
+    '  return result;',
+    '};'
+    ]),
+    '');
+end;
+
+procedure TTestModule.TestNestedProc;
+begin
+  StartProgram(false);
+  Add('function DoIt(a,d: longint): longint;');
+  Add('var');
+  Add('  b: longint;');
+  Add('  c: longint;');
+  Add('  function Nesty(a: longint): longint; ');
+  Add('  var b: longint;');
+  Add('  begin');
+  Add('    Result:=a+b+c+d;');
+  Add('  end;');
+  Add('begin');
+  Add('  Result:=a+b+c;');
+  Add('end;');
+  Add('begin');
+  ConvertProgram;
+  CheckSource('TestNestedProc',
+    LinesToStr([ // statements
+    'this.doit = function (a, d) {',
+    '  var result = 0;',
+    '  var b = 0;',
+    '  var c = 0;',
+    '  function nesty(a) {',
+    '    var result = 0;',
+    '    var b = 0;',
+    '    result = (((a + b) + c) + d);',
+    '    return result;',
+    '  };',
+    '  result = ((a + b) + c);',
+    '  return result;',
+    '};'
+    ]),
+    '');
+end;
+
+procedure TTestModule.TestForwardProc;
+begin
+  StartProgram(false);
+  Add('procedure FuncA(i: longint); forward;');
+  Add('procedure FuncB(i: longint);');
+  Add('begin');
+  Add('  FuncA(i);');
+  Add('end;');
+  Add('procedure FuncA(i: longint);');
+  Add('begin');
+  Add('  if i=3 then ;');
+  Add('end;');
+  Add('begin');
+  Add('  FuncA(4);');
+  Add('  FuncB(5);');
+  ConvertProgram;
+  CheckSource('TestForwardProc',
+    LinesToStr([ // statements'
+    'this.funcb = function (i) {',
+    '  this.funca(i);',
+    '};',
+    'this.funca = function (i) {',
+    '  if ((i == 3)) {',
+    '  };',
+    '};'
+    ]),
+    LinesToStr([
+    'this.funca(4);',
+    'this.funcb(5);'
+    ])
+    );
+end;
+
+procedure TTestModule.TestNestedForwardProc;
+begin
+  StartProgram(false);
+  Add('procedure FuncA;');
+  Add('  procedure FuncB(i: longint); forward;');
+  Add('  procedure FuncC(i: longint);');
+  Add('  begin');
+  Add('    FuncB(i);');
+  Add('  end;');
+  Add('  procedure FuncB(i: longint);');
+  Add('  begin');
+  Add('    if i=3 then ;');
+  Add('  end;');
+  Add('begin');
+  Add('  FuncC(4)');
+  Add('end;');
+  Add('begin');
+  Add('  FuncA;');
+  ConvertProgram;
+  CheckSource('TestNestedForwardProc',
+    LinesToStr([ // statements'
+    'this.funca = function () {',
+    '  function funcc(i) {',
+    '    funcb(i);',
+    '  };',
+    '  function funcb(i) {',
+    '    if ((i == 3)) {',
+    '    };',
+    '  };',
+    '  funcc(4);',
+    '};'
+    ]),
+    LinesToStr([
+    'this.funca();'
+    ])
+    );
+end;
+
+procedure TTestModule.TestAssignFunctionResult;
+begin
+  StartProgram(false);
+  Add('function F1: longint;');
+  Add('begin');
+  Add('end;');
+  Add('var i: longint;');
+  Add('begin');
+  Add('  i:=F1();');
+  Add('  i:=F1()+F1();');
+  ConvertProgram;
+  CheckSource('TestAssignFunctionResult',
+    LinesToStr([ // statements
+     'this.f1 = function () {',
+     '  var result = 0;',
+     '  return result;',
+     '};',
+     'this.i = 0;'
+    ]),
+    LinesToStr([
+    'this.i = this.f1();',
+    'this.i = (this.f1() + this.f1());'
+    ]));
+end;
+
+procedure TTestModule.TestFunctionResultInCondition;
+begin
+  StartProgram(false);
+  Add('function F1: longint;');
+  Add('begin');
+  Add('end;');
+  Add('function F2: boolean;');
+  Add('begin');
+  Add('end;');
+  Add('var i: longint;');
+  Add('begin');
+  Add('  if F2 then ;');
+  Add('  if i=F1() then ;');
+  Add('  if i=F1 then ;');
+  ConvertProgram;
+  CheckSource('TestFunctionResultInCondition',
+    LinesToStr([ // statements
+     'this.f1 = function () {',
+     '  var result = 0;',
+     '  return result;',
+     '};',
+     'this.f2 = function () {',
+     '  var result = false;',
+     '  return result;',
+     '};',
+     'this.i = 0;'
+    ]),
+    LinesToStr([
+    'if (this.f2()) {',
+    '};',
+    'if ((this.i == this.f1())) {',
+    '};',
+    'if ((this.i == this.f1())) {',
+    '};'
+    ]));
+end;
+
+procedure TTestModule.TestExit;
+begin
+  StartProgram(false);
+  Add('procedure ProcA;');
+  Add('begin');
+  Add('  exit;');
+  Add('end;');
+  Add('function FuncB: longint;');
+  Add('begin');
+  Add('  exit;');
+  Add('  exit(3);');
+  Add('end;');
+  Add('function FuncC: string;');
+  Add('begin');
+  Add('  exit;');
+  Add('  exit(''a'');');
+  Add('  exit(''abc'');');
+  Add('end;');
+  Add('begin');
+  ConvertProgram;
+  CheckSource('TestUnitImplVar',
+    LinesToStr([ // statements
+    'this.proca = function () {',
+    '  return;',
+    '};',
+    'this.funcb = function () {',
+    '  var result = 0;',
+    '  return result;',
+    '  return 3;',
+    '  return result;',
+    '};',
+    'this.funcc = function () {',
+    '  var result = "";',
+    '  return result;',
+    '  return "a";',
+    '  return "abc";',
+    '  return result;',
+    '};'
+    ]),
+    '');
+end;
+
 procedure TTestModule.TestUnitImplVars;
 begin
   StartUnit(false);
@@ -1018,7 +1381,7 @@ begin
   ConvertUnit;
   CheckSource('TestUnitImplVar',
     LinesToStr([ // statements
-    ' var $impl = {',
+    'var $impl = {',
     '};',
     'this.$impl = $impl;',
     '$impl.v1 = 0;',
@@ -1277,7 +1640,7 @@ begin
     'this.i = 0;'
     ]),
     LinesToStr([ // this.$main
-    '  this.i = 1;',
+    'this.i = 1;',
     'if (i==1) {',
     'i=2;',
     '}',