pastojs: low/high(astring)

This commit is contained in:
mattias 2021-06-03 17:11:04 +00:00
parent 2212fd0fcf
commit 7863f634c7
5 changed files with 105 additions and 38 deletions

View File

@ -1806,6 +1806,8 @@ type
procedure OnRangeCheckEl(Sender: TResExprEvaluator; El: TPasElement; procedure OnRangeCheckEl(Sender: TResExprEvaluator; El: TPasElement;
var MsgType: TMessageType); virtual; var MsgType: TMessageType); virtual;
function EvalBaseTypeCast(Params: TParamsExpr; bt: TResolverBaseType): TResEvalvalue; function EvalBaseTypeCast(Params: TParamsExpr; bt: TResolverBaseType): TResEvalvalue;
function EvalLengthOfString(ParamResolved: TPasResolverResult;
Param: TPasExpr; Flags: TResEvalFlags): TResEvalValue; virtual;
protected protected
// generic/specialize // generic/specialize
type type
@ -14822,6 +14824,7 @@ begin
'0'..'9': i:=i*base+ord(Value[p])-ord('0'); '0'..'9': i:=i*base+ord(Value[p])-ord('0');
'A'..'Z': i:=i*base+ord(Value[p])-ord('A')+10; 'A'..'Z': i:=i*base+ord(Value[p])-ord('A')+10;
'a'..'z': i:=i*base+ord(Value[p])-ord('a')+10; 'a'..'z': i:=i*base+ord(Value[p])-ord('a')+10;
else break;
end; end;
inc(p); inc(p);
end; end;
@ -15903,6 +15906,28 @@ begin
end; end;
end; end;
function TPasResolver.EvalLengthOfString(ParamResolved: TPasResolverResult;
Param: TPasExpr; Flags: TResEvalFlags): TResEvalValue;
var
Value: TResEvalValue;
begin
Result:=nil;
if rrfReadable in ParamResolved.Flags then
begin
Value:=Eval(Param,Flags);
if Value=nil then exit;
case Value.Kind of
{$ifdef FPC_HAS_CPSTRING}
revkString:
Result:=TResEvalInt.CreateValue(length(TResEvalString(Value).S));
{$endif}
revkUnicodeString:
Result:=TResEvalInt.CreateValue(length(TResEvalUTF16(Value).S));
end;
ReleaseEvalValue(Value);
end
end;
procedure TPasResolver.AddGenericTemplateIdentifiers( procedure TPasResolver.AddGenericTemplateIdentifiers(
GenericTemplateTypes: TFPList; Scope: TPasIdentifierScope); GenericTemplateTypes: TFPList; Scope: TPasIdentifierScope);
var var
@ -18672,7 +18697,6 @@ procedure TPasResolver.BI_Length_OnEval(Proc: TResElDataBuiltInProc;
var var
Param, Expr: TPasExpr; Param, Expr: TPasExpr;
ParamResolved: TPasResolverResult; ParamResolved: TPasResolverResult;
Value: TResEvalValue;
Ranges: TPasExprArray; Ranges: TPasExprArray;
IdentEl: TPasElement; IdentEl: TPasElement;
begin begin
@ -18681,22 +18705,7 @@ begin
Param:=Params.Params[0]; Param:=Params.Params[0];
ComputeElement(Param,ParamResolved,[]); ComputeElement(Param,ParamResolved,[]);
if ParamResolved.BaseType in btAllStringAndChars then if ParamResolved.BaseType in btAllStringAndChars then
begin Evaluated:=EvalLengthOfString(ParamResolved,Param,Flags)
if rrfReadable in ParamResolved.Flags then
begin
Value:=Eval(Param,Flags);
if Value=nil then exit;
case Value.Kind of
{$ifdef FPC_HAS_CPSTRING}
revkString:
Evaluated:=TResEvalInt.CreateValue(length(TResEvalString(Value).S));
{$endif}
revkUnicodeString:
Evaluated:=TResEvalInt.CreateValue(length(TResEvalUTF16(Value).S));
end;
ReleaseEvalValue(Value);
end
end
else if ParamResolved.BaseType=btContext then else if ParamResolved.BaseType=btContext then
begin begin
if (ParamResolved.LoTypeEl.ClassType=TPasArrayType) then if (ParamResolved.LoTypeEl.ClassType=TPasArrayType) then
@ -19262,6 +19271,7 @@ var
Param: TPasExpr; Param: TPasExpr;
ParamResolved: TPasResolverResult; ParamResolved: TPasResolverResult;
C: TClass; C: TClass;
bt: TResolverBaseType;
begin begin
if not CheckBuiltInMinParamCount(Proc,Expr,1,RaiseOnError) then if not CheckBuiltInMinParamCount(Proc,Expr,1,RaiseOnError) then
exit(cIncompatible); exit(cIncompatible);
@ -19271,12 +19281,15 @@ begin
Param:=Params.Params[0]; Param:=Params.Params[0];
ComputeElement(Param,ParamResolved,[]); ComputeElement(Param,ParamResolved,[]);
Result:=cIncompatible; Result:=cIncompatible;
if ParamResolved.BaseType in btAllRanges then bt:=ParamResolved.BaseType;
if bt in btAllRanges then
// e.g. high(char) // e.g. high(char)
Result:=cExact Result:=cExact
else if ParamResolved.BaseType=btSet then else if bt=btSet then
Result:=cExact Result:=cExact
else if (ParamResolved.BaseType=btContext) then else if bt in btAllStrings then
Result:=cExact
else if (bt=btContext) then
begin begin
C:=ParamResolved.LoTypeEl.ClassType; C:=ParamResolved.LoTypeEl.ClassType;
if (C=TPasArrayType) if (C=TPasArrayType)
@ -19332,6 +19345,12 @@ begin
ResolvedEl.BaseType:=ResolvedEl.SubType; ResolvedEl.BaseType:=ResolvedEl.SubType;
ResolvedEl.SubType:=btNone; ResolvedEl.SubType:=btNone;
end end
else if ResolvedEl.BaseType in btAllStrings then
begin
// high(aString)
SetResolverIdentifier(ResolvedEl,BaseTypeLength,Proc.Proc,
FBaseTypes[BaseTypeLength],FBaseTypes[BaseTypeLength],[rrfReadable]);
end
else else
;// ordinal: result type is argument type ;// ordinal: result type is argument type
ResolvedEl.Flags:=ResolvedEl.Flags-[rrfWritable]+[rrfReadable]; ResolvedEl.Flags:=ResolvedEl.Flags-[rrfWritable]+[rrfReadable];
@ -19511,6 +19530,13 @@ begin
else else
Evaluated:=TResEvalUTF16.CreateValue(#$ffff); Evaluated:=TResEvalUTF16.CreateValue(#$ffff);
end end
else if bt in btAllStrings then
begin
if Proc.BuiltIn=bfLow then
Evaluated:=TResEvalInt.CreateValue(1)
else
Evaluated:=EvalLengthOfString(ParamResolved,Param,Flags);
end
else else
begin begin
{$IFDEF VerbosePasResolver} {$IFDEF VerbosePasResolver}
@ -19524,6 +19550,13 @@ begin
// e.g. type t = 2..10; // e.g. type t = 2..10;
Evaluated:=EvalRangeLimit(TPasRangeType(TypeEl).RangeExpr,FLags,Proc.BuiltIn=bfLow,Param); Evaluated:=EvalRangeLimit(TPasRangeType(TypeEl).RangeExpr,FLags,Proc.BuiltIn=bfLow,Param);
end end
else if ParamResolved.BaseType in btAllStrings then
begin
if Proc.BuiltIn=bfLow then
Evaluated:=TResEvalInt.CreateValue(1)
else
Evaluated:=EvalLengthOfString(ParamResolved,Param,Flags);
end
else else
begin begin
{$IFDEF VerbosePasResolver} {$IFDEF VerbosePasResolver}

View File

@ -4948,14 +4948,21 @@ end;
procedure TTestResolver.TestHighLow; procedure TTestResolver.TestHighLow;
begin begin
StartProgram(false); StartProgram(false);
Add('var'); Add([
Add(' bo: boolean;'); 'const',
Add(' by: byte;'); ' abc = ''abc'';',
Add(' ch: char;'); 'var',
Add('begin'); ' bo: boolean;',
Add(' for bo:=low(boolean) to high(boolean) do;'); ' by: byte;',
Add(' for by:=low(byte) to high(byte) do;'); ' ch: char;',
Add(' for ch:=low(char) to high(char) do;'); ' s: string;',
' i: longint = high(abc);',
'begin',
' for bo:=low(boolean) to high(boolean) do;',
' for by:=low(byte) to high(byte) do;',
' for ch:=low(char) to high(char) do;',
' for i:=low(s) to high(s) do;',
'']);
ParseProgram; ParseProgram;
end; end;

View File

@ -2015,10 +2015,12 @@ type
Function CreateCallCharCodeAt(Arg: TJSElement; aNumber: integer; El: TPasElement): TJSCallExpression; virtual; Function CreateCallCharCodeAt(Arg: TJSElement; aNumber: integer; El: TPasElement): TJSCallExpression; virtual;
Function CreateCallFromCharCode(Arg: TJSElement; El: TPasElement): TJSCallExpression; virtual; Function CreateCallFromCharCode(Arg: TJSElement; El: TPasElement): TJSCallExpression; virtual;
Function CreateUsesList(UsesSection: TPasSection; AContext : TConvertContext): TJSArrayLiteral; Function CreateUsesList(UsesSection: TPasSection; AContext : TConvertContext): TJSArrayLiteral;
// js statement list
Procedure AddToStatementList(var First, Last: TJSStatementList; Procedure AddToStatementList(var First, Last: TJSStatementList;
Add: TJSElement; Src: TPasElement); overload; Add: TJSElement; Src: TPasElement); overload;
Procedure AddToStatementList(St: TJSStatementList; Add: TJSElement; Src: TPasElement); overload; Procedure AddToStatementList(St: TJSStatementList; Add: TJSElement; Src: TPasElement); overload;
Procedure PrependToStatementList(var St: TJSElement; Add: TJSElement; PosEl: TPasElement); Procedure PrependToStatementList(var St: TJSElement; Add: TJSElement; PosEl: TPasElement);
// js var
Procedure AddToVarStatement(VarStat: TJSVariableStatement; Add: TJSElement; Procedure AddToVarStatement(VarStat: TJSVariableStatement; Add: TJSElement;
Src: TPasElement); Src: TPasElement);
Function CreateValInit(PasType: TPasType; Expr: TPasExpr; El: TPasElement; Function CreateValInit(PasType: TPasType; Expr: TPasExpr; El: TPasElement;
@ -2027,6 +2029,15 @@ type
Function CreateVarStatement(const aName: String; Init: TJSElement; Function CreateVarStatement(const aName: String; Init: TJSElement;
El: TPasElement): TJSVariableStatement; virtual; El: TPasElement): TJSVariableStatement; virtual;
Function CreateVarDecl(const aName: String; Init: TJSElement; El: TPasElement): TJSVarDeclaration; virtual; Function CreateVarDecl(const aName: String; Init: TJSElement; El: TPasElement): TJSVarDeclaration; virtual;
// misc
Function CreateExternalBracketAccessorCall(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
Function CreateAssignStatement(LeftEl: TPasExpr; AssignContext: TAssignContext): TJSElement; virtual;
Function CreateGetEnumeratorLoop(El: TPasImplForLoop;
AContext: TConvertContext): TJSElement; virtual;
Function CreateCallRTLFreeLoc(Setter, Getter: TJSElement; Src: TPasElement): TJSElement; virtual;
Function CreateDotSplit(El: TPasElement; Expr: TJSElement): TJSElement; virtual;
Function CreatePrecompiledJS(El: TJSElement): string; virtual;
Procedure AddRTLVersionCheck(FuncContext: TFunctionContext; PosEl: TPasElement);
// JS literals // JS literals
Function CreateLiteralNumber(El: TPasElement; const n: TJSNumber): TJSLiteral; virtual; Function CreateLiteralNumber(El: TPasElement; const n: TJSNumber): TJSLiteral; virtual;
Function CreateLiteralFloat(El: TPasElement; const n: TJSNumber): TJSElement; virtual; Function CreateLiteralFloat(El: TPasElement; const n: TJSNumber): TJSElement; virtual;
@ -2116,25 +2127,18 @@ type
Procedure AddClassConstructors(FuncContext: TFunctionContext; PosEl: TPasElement); virtual; Procedure AddClassConstructors(FuncContext: TFunctionContext; PosEl: TPasElement); virtual;
Procedure AddClassMessageIds(El: TPasClassType; Src: TJSSourceElements; Procedure AddClassMessageIds(El: TPasClassType; Src: TJSSourceElements;
FuncContext: TFunctionContext; pbivn: TPas2JSBuiltInName); virtual; FuncContext: TFunctionContext; pbivn: TPas2JSBuiltInName); virtual;
// misc // callbacks
Function CreateCallback(Expr: TPasExpr; ResolvedEl: TPasResolverResult; Function CreateCallback(Expr: TPasExpr; ResolvedEl: TPasResolverResult;
aSafeCall: boolean; AContext: TConvertContext): TJSElement; virtual; aSafeCall: boolean; AContext: TConvertContext): TJSElement; virtual;
Function CreateSafeCallback(Expr: TPasExpr; JS: TJSElement; AContext: TConvertContext): TJSElement; virtual; Function CreateSafeCallback(Expr: TPasExpr; JS: TJSElement; AContext: TConvertContext): TJSElement; virtual;
Function CreateExternalBracketAccessorCall(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual; // property
Function CreateAssignStatement(LeftEl: TPasExpr; AssignContext: TAssignContext): TJSElement; virtual;
Function CreateGetEnumeratorLoop(El: TPasImplForLoop;
AContext: TConvertContext): TJSElement; virtual;
Function CreateCallRTLFreeLoc(Setter, Getter: TJSElement; Src: TPasElement): TJSElement; virtual;
Function CreatePropertyGet(Prop: TPasProperty; Expr: TPasExpr; Function CreatePropertyGet(Prop: TPasProperty; Expr: TPasExpr;
AContext: TConvertContext; PosEl: TPasElement): TJSElement; virtual; AContext: TConvertContext; PosEl: TPasElement): TJSElement; virtual;
Function AppendPropertyAssignArgs(Call: TJSCallExpression; Prop: TPasProperty; Function AppendPropertyAssignArgs(Call: TJSCallExpression; Prop: TPasProperty;
AssignContext: TAssignContext; PosEl: TPasElement): TJSCallExpression; virtual; AssignContext: TAssignContext; PosEl: TPasElement): TJSCallExpression; virtual;
Function AppendPropertyReadArgs(Call: TJSCallExpression; Prop: TPasProperty; Function AppendPropertyReadArgs(Call: TJSCallExpression; Prop: TPasProperty;
aContext: TConvertContext; PosEl: TPasElement): TJSCallExpression; virtual; aContext: TConvertContext; PosEl: TPasElement): TJSCallExpression; virtual;
Function CreateDotSplit(El: TPasElement; Expr: TJSElement): TJSElement; virtual;
Function CreatePrecompiledJS(El: TJSElement): string; virtual;
Function CreateRaisePropReadOnly(PosEl: TPasElement): TJSElement; virtual; Function CreateRaisePropReadOnly(PosEl: TPasElement): TJSElement; virtual;
Procedure AddRTLVersionCheck(FuncContext: TFunctionContext; PosEl: TPasElement);
// create elements for RTTI // create elements for RTTI
Function CreateTypeInfoRef(El: TPasType; AContext: TConvertContext; Function CreateTypeInfoRef(El: TPasType; AContext: TConvertContext;
ErrorEl: TPasElement): TJSElement; virtual; ErrorEl: TPasElement): TJSElement; virtual;
@ -13687,6 +13691,20 @@ begin
exit; exit;
end; end;
end; end;
btString:
begin
writeln('AAA1 TPasToJSConverter.ConvertBuiltIn_LowHigh ',IsLow);
if isLow then
// low(aString) -> 1
Result:=CreateLiteralNumber(El,1)
else
begin
// high(aString) -> aString.length
Result:=ConvertExpression(Param,AContext);
Result:=CreateDotNameExpr(El,Result,'length');
end;
exit;
end;
end; end;
DoError(20170210110717,nXExpectedButYFound,sXExpectedButYFound,['enum or array', DoError(20170210110717,nXExpectedButYFound,sXExpectedButYFound,['enum or array',
AContext.Resolver.GetResolverResultDescription(ResolvedEl)],Param); AContext.Resolver.GetResolverResultDescription(ResolvedEl)],Param);
@ -19672,6 +19690,7 @@ end;
function TPasToJSConverter.CreateDotSplit(El: TPasElement; Expr: TJSElement function TPasToJSConverter.CreateDotSplit(El: TPasElement; Expr: TJSElement
): TJSElement; ): TJSElement;
// create Expr.split('')
var var
DotExpr: TJSDotMemberExpression; DotExpr: TJSDotMemberExpression;
Call: TJSCallExpression; Call: TJSCallExpression;

View File

@ -81,7 +81,7 @@ unit Pas2JsFiler;
{$mode objfpc}{$H+} {$mode objfpc}{$H+}
{$IF FPC_FULLVERSION>30200} {$IF FPC_FULLVERSION>=30300}
{$WARN 6060 off : case statement does not handle all possible cases} {$WARN 6060 off : case statement does not handle all possible cases}
{$ENDIF} {$ENDIF}

View File

@ -7815,8 +7815,11 @@ begin
' c = string(''ä'');', ' c = string(''ä'');',
' d = UnicodeString(''b'');', ' d = UnicodeString(''b'');',
' e = UnicodeString(''ö'');', ' e = UnicodeString(''ö'');',
' f = low(a)+high(b);',
' g: word = low(a);',
'var', 'var',
' s: string = ''abc'';', ' s: string = ''abc'';',
' i: longint;',
'begin', 'begin',
' s:='''';', ' s:='''';',
' s:=#13#10;', ' s:=#13#10;',
@ -7835,6 +7838,7 @@ begin
' s:=concat(s);', ' s:=concat(s);',
' s:=concat(s,''a'',s);', ' s:=concat(s,''a'',s);',
' s:=#250#269;', ' s:=#250#269;',
' i:=low(s)+high(a);',
//' s:=#$2F804;', //' s:=#$2F804;',
// ToDo: \uD87E\uDC04 -> \u{2F804} // ToDo: \uD87E\uDC04 -> \u{2F804}
'']); '']);
@ -7846,7 +7850,10 @@ begin
'this.c = "ä";', 'this.c = "ä";',
'this.d = "b";', 'this.d = "b";',
'this.e = "ö";', 'this.e = "ö";',
'this.f = 1 + this.b.length;',
'this.g = 1;',
'this.s="abc";', 'this.s="abc";',
'this.i = 0;',
'']), '']),
LinesToStr([ LinesToStr([
'$mod.s="";', '$mod.s="";',
@ -7866,6 +7873,7 @@ begin
'$mod.s = $mod.s;', '$mod.s = $mod.s;',
'$mod.s = $mod.s.concat("a", $mod.s);', '$mod.s = $mod.s.concat("a", $mod.s);',
'$mod.s = "úč";', '$mod.s = "úč";',
'$mod.i = 1 + $mod.a.length;',
''])); '']));
end; end;