@@ -4,6 +4,8 @@ import * as bytes from "@goscript/bytes/index.ts"
44
55import * as fmt from "@goscript/fmt/index.ts"
66
7+ import * as scannerhooks from "@goscript/go/internal/scannerhooks/index.ts"
8+
79import * as token from "@goscript/go/token/index.ts"
810
911import * as filepath from "@goscript/path/filepath/index.ts"
@@ -121,19 +123,12 @@ export class Scanner {
121123 this . _fields . nlPos . value = value
122124 }
123125
124- public get endPosValid ( ) : boolean {
125- return this . _fields . endPosValid . value
126- }
127- public set endPosValid ( value : boolean ) {
128- this . _fields . endPosValid . value = value
129- }
130-
131- // overrides the offset as the default end position
132- public get endPos ( ) : token . Pos {
133- return this . _fields . endPos . value
126+ // end position; defined only for STRING tokens
127+ public get stringEnd ( ) : token . Pos {
128+ return this . _fields . stringEnd . value
134129 }
135- public set endPos ( value : token . Pos ) {
136- this . _fields . endPos . value = value
130+ public set stringEnd ( value : token . Pos ) {
131+ this . _fields . stringEnd . value = value
137132 }
138133
139134 // public state - ok to modify
@@ -157,12 +152,11 @@ export class Scanner {
157152 lineOffset : $ . VarRef < number > ;
158153 insertSemi : $ . VarRef < boolean > ;
159154 nlPos : $ . VarRef < token . Pos > ;
160- endPosValid : $ . VarRef < boolean > ;
161- endPos : $ . VarRef < token . Pos > ;
155+ stringEnd : $ . VarRef < token . Pos > ;
162156 ErrorCount : $ . VarRef < number > ;
163157 }
164158
165- constructor ( init ?: Partial < { ErrorCount ?: number , ch ?: number , dir ?: string , endPos ?: token . Pos , endPosValid ?: boolean , err ?: ErrorHandler | null , file ?: token . File | null , insertSemi ?: boolean , lineOffset ?: number , mode ?: Mode , nlPos ?: token . Pos , offset ?: number , rdOffset ?: number , src ?: $ . Bytes } > ) {
159+ constructor ( init ?: Partial < { ErrorCount ?: number , ch ?: number , dir ?: string , err ?: ErrorHandler | null , file ?: token . File | null , insertSemi ?: boolean , lineOffset ?: number , mode ?: Mode , nlPos ?: token . Pos , offset ?: number , rdOffset ?: number , src ?: $ . Bytes , stringEnd ?: token . Pos } > ) {
166160 this . _fields = {
167161 file : $ . varRef ( init ?. file ?? null ) ,
168162 dir : $ . varRef ( init ?. dir ?? "" ) ,
@@ -175,8 +169,7 @@ export class Scanner {
175169 lineOffset : $ . varRef ( init ?. lineOffset ?? 0 ) ,
176170 insertSemi : $ . varRef ( init ?. insertSemi ?? false ) ,
177171 nlPos : $ . varRef ( init ?. nlPos ?? 0 as token . Pos ) ,
178- endPosValid : $ . varRef ( init ?. endPosValid ?? false ) ,
179- endPos : $ . varRef ( init ?. endPos ?? 0 as token . Pos ) ,
172+ stringEnd : $ . varRef ( init ?. stringEnd ?? 0 as token . Pos ) ,
180173 ErrorCount : $ . varRef ( init ?. ErrorCount ?? 0 )
181174 }
182175 }
@@ -195,8 +188,7 @@ export class Scanner {
195188 lineOffset : $ . varRef ( this . _fields . lineOffset . value ) ,
196189 insertSemi : $ . varRef ( this . _fields . insertSemi . value ) ,
197190 nlPos : $ . varRef ( this . _fields . nlPos . value ) ,
198- endPosValid : $ . varRef ( this . _fields . endPosValid . value ) ,
199- endPos : $ . varRef ( this . _fields . endPos . value ) ,
191+ stringEnd : $ . varRef ( this . _fields . stringEnd . value ) ,
200192 ErrorCount : $ . varRef ( this . _fields . ErrorCount . value )
201193 }
202194 return cloned
@@ -292,8 +284,20 @@ export class Scanner {
292284 if ( file ! . Size ( ) != $ . len ( src ) ) {
293285 $ . panic ( fmt . Sprintf ( "file size (%d) does not match src len (%d)" , file ! . Size ( ) , $ . len ( src ) ) )
294286 }
295- let [ dir , ] = filepath . Split ( file ! . Name ( ) )
296- s ! . value = $ . markAsStructValue ( new Scanner ( { ch : 32 , dir : dir , endPos : token . NoPos , endPosValid : true , err : err , file : file , mode : mode , src : src } ) )
287+ s . file = file
288+ {
289+ const _tmp = filepath . Split ( file ! . Name ( ) )
290+ s . dir = _tmp [ 0 ]
291+ }
292+ s . src = src
293+ s . err = err
294+ s . mode = mode
295+ s . ch = 32
296+ s . offset = 0
297+ s . rdOffset = 0
298+ s . lineOffset = 0
299+ s . insertSemi = false
300+ s . ErrorCount = 0
297301 await s . next ( )
298302 if ( Number ( s . ch ) == 65279 ) {
299303 await s . next ( ) // ignore BOM at file beginning
@@ -754,7 +758,7 @@ export class Scanner {
754758 return $ . bytesToString ( $ . goSlice ( s . src , offs , s . offset ) )
755759 }
756760
757- public async scanRawString ( ) : Promise < string > {
761+ public async scanRawString ( ) : Promise < [ string , number ] > {
758762 const s = this
759763 let offs = s . offset - 1
760764 let hasCR = false
@@ -773,10 +777,11 @@ export class Scanner {
773777 }
774778 }
775779 let lit = $ . goSlice ( s . src , offs , s . offset )
780+ let rawLen = $ . len ( lit )
776781 if ( hasCR ) {
777782 lit = stripCR ( lit , false )
778783 }
779- return $ . bytesToString ( lit )
784+ return [ $ . bytesToString ( lit ) , rawLen ]
780785 }
781786
782787 public async skipWhitespace ( ) : Promise < void > {
@@ -825,16 +830,6 @@ export class Scanner {
825830 return tok0
826831 }
827832
828- // End returns the position immediately after the last scanned token.
829- // If [Scanner.Scan] has not been called yet, End returns [token.NoPos].
830- public End ( ) : token . Pos {
831- const s = this
832- if ( s . endPosValid ) {
833- return s . endPos
834- }
835- return s . file ! . Pos ( s . offset )
836- }
837-
838833 // Scan scans the next token and returns the token position, the token,
839834 // and its literal string if applicable. The source end is indicated by
840835 // [token.EOF].
@@ -848,9 +843,7 @@ export class Scanner {
848843 // If the returned token is [token.SEMICOLON], the corresponding
849844 // literal string is ";" if the semicolon was present in the source,
850845 // and "\n" if the semicolon was inserted because of a newline or
851- // at EOF. If the newline is within a /*...*/ comment, the SEMICOLON token
852- // is synthesized immediately after the COMMENT token; its position is that
853- // of the actual newline within the comment.
846+ // at EOF.
854847 //
855848 // If the returned token is [token.ILLEGAL], the literal string is the
856849 // offending character.
@@ -872,13 +865,10 @@ export class Scanner {
872865 let pos : token . Pos = 0
873866 let tok : token . Token = 0
874867 let lit : string = ""
875- scanAgain: s . endPosValid = false
876- if ( token . Pos_IsValid ( s . nlPos ) ) {
868+ scanAgain: if ( token . Pos_IsValid ( s . nlPos ) ) {
877869 // Return artificial ';' token after /*...*/ comment
878870 // containing newline, at position of first newline.
879871 ; [ pos , tok , lit ] = [ s . nlPos , token . SEMICOLON , "\n" ]
880- s . endPos = pos + 1
881- s . endPosValid = true
882872 s . nlPos = token . NoPos
883873 return [ pos , tok , lit ]
884874 }
@@ -932,6 +922,7 @@ export class Scanner {
932922 insertSemi = true
933923 tok = token . STRING
934924 lit = await s . scanString ( )
925+ s . stringEnd = pos + ( $ . len ( lit ) as token . Pos )
935926 break
936927 }
937928 case 39 : {
@@ -943,7 +934,9 @@ export class Scanner {
943934 case 96 : {
944935 insertSemi = true
945936 tok = token . STRING
946- lit = await s . scanRawString ( )
937+ let rawLen : number = 0
938+ ; [ lit , rawLen ] = await s . scanRawString ( )
939+ s . stringEnd = pos + ( rawLen as token . Pos )
947940 break
948941 }
949942 case 58 : {
@@ -1119,14 +1112,21 @@ export class Scanner {
11191112 static __typeInfo = $ . registerStructType (
11201113 'go/scanner.Scanner' ,
11211114 new Scanner ( ) ,
1122- [ { name : "next" , args : [ ] , returns : [ ] } , { name : "peek" , args : [ ] , returns : [ { type : { kind : $ . TypeKind . Basic , name : "byte" } } ] } , { name : "Init" , args : [ { name : "file" , type : { kind : $ . TypeKind . Pointer , elemType : "go/token.File" } } , { name : "src" , type : { kind : $ . TypeKind . Slice , elemType : { kind : $ . TypeKind . Basic , name : "byte" } } } , { name : "err" , type : "go/scanner.ErrorHandler" } , { name : "mode" , type : "go/scanner.Mode" } ] , returns : [ ] } , { name : "error" , args : [ { name : "offs" , type : { kind : $ . TypeKind . Basic , name : "int" } } , { name : "msg" , type : { kind : $ . TypeKind . Basic , name : "string" } } ] , returns : [ ] } , { name : "errorf" , args : [ { name : "offs" , type : { kind : $ . TypeKind . Basic , name : "int" } } , { name : "format" , type : { kind : $ . TypeKind . Basic , name : "string" } } , { name : "args" , type : { kind : $ . TypeKind . Slice , elemType : { kind : $ . TypeKind . Interface , methods : [ ] } } } ] , returns : [ ] } , { name : "scanComment" , args : [ ] , returns : [ { type : { kind : $ . TypeKind . Basic , name : "string" } } , { type : { kind : $ . TypeKind . Basic , name : "int" } } ] } , { name : "updateLineInfo" , args : [ { name : "next" , type : { kind : $ . TypeKind . Basic , name : "int" } } , { name : "offs" , type : { kind : $ . TypeKind . Basic , name : "int" } } , { name : "text" , type : { kind : $ . TypeKind . Slice , elemType : { kind : $ . TypeKind . Basic , name : "byte" } } } ] , returns : [ ] } , { name : "scanIdentifier" , args : [ ] , returns : [ { type : { kind : $ . TypeKind . Basic , name : "string" } } ] } , { name : "digits" , args : [ { name : "base" , type : { kind : $ . TypeKind . Basic , name : "int" } } , { name : "invalid" , type : { kind : $ . TypeKind . Pointer , elemType : { kind : $ . TypeKind . Basic , name : "int" } } } ] , returns : [ { type : { kind : $ . TypeKind . Basic , name : "int" } } ] } , { name : "scanNumber" , args : [ ] , returns : [ { type : "go/token.Token" } , { type : { kind : $ . TypeKind . Basic , name : "string" } } ] } , { name : "scanEscape" , args : [ { name : "quote" , type : { kind : $ . TypeKind . Basic , name : "rune" } } ] , returns : [ { type : { kind : $ . TypeKind . Basic , name : "bool" } } ] } , { name : "scanRune" , args : [ ] , returns : [ { type : { kind : $ . TypeKind . Basic , name : "string" } } ] } , { name : "scanString" , args : [ ] , returns : [ { type : { kind : $ . TypeKind . Basic , name : "string" } } ] } , { name : "scanRawString" , args : [ ] , returns : [ { type : { kind : $ . TypeKind . Basic , name : "string" } } ] } , { name : "skipWhitespace" , args : [ ] , returns : [ ] } , { name : "switch2" , args : [ { name : "tok0" , type : "go/token.Token" } , { name : "tok1" , type : "go/token.Token" } ] , returns : [ { type : "go/token.Token" } ] } , { name : "switch3" , args : [ { name : "tok0" , type : "go/token.Token" } , { name : "tok1" , type : "go/token.Token" } , { name : "ch2" , type : { kind : $ . TypeKind . Basic , name : "rune" } } , { name : "tok2" , type : "go/token.Token" } ] , returns : [ { type : "go/token.Token" } ] } , { name : "switch4" , args : [ { name : "tok0" , type : "go/token.Token" } , { name : "tok1" , type : "go/token.Token" } , { name : "ch2" , type : { kind : $ . TypeKind . Basic , name : "rune" } } , { name : "tok2" , type : "go/token.Token" } , { name : "tok3" , type : "go/token.Token" } ] , returns : [ { type : "go/token.Token" } ] } , { name : "End" , args : [ ] , returns : [ { type : "go/token.Pos" } ] } , { name : "Scan" , args : [ ] , returns : [ { type : "go/token.Pos" } , { type : "go/token.Token" } , { type : { kind : $ . TypeKind . Basic , name : "string" } } ] } ] ,
1115+ [ { name : "next" , args : [ ] , returns : [ ] } , { name : "peek" , args : [ ] , returns : [ { type : { kind : $ . TypeKind . Basic , name : "byte" } } ] } , { name : "Init" , args : [ { name : "file" , type : { kind : $ . TypeKind . Pointer , elemType : "go/token.File" } } , { name : "src" , type : { kind : $ . TypeKind . Slice , elemType : { kind : $ . TypeKind . Basic , name : "byte" } } } , { name : "err" , type : "go/scanner.ErrorHandler" } , { name : "mode" , type : "go/scanner.Mode" } ] , returns : [ ] } , { name : "error" , args : [ { name : "offs" , type : { kind : $ . TypeKind . Basic , name : "int" } } , { name : "msg" , type : { kind : $ . TypeKind . Basic , name : "string" } } ] , returns : [ ] } , { name : "errorf" , args : [ { name : "offs" , type : { kind : $ . TypeKind . Basic , name : "int" } } , { name : "format" , type : { kind : $ . TypeKind . Basic , name : "string" } } , { name : "args" , type : { kind : $ . TypeKind . Slice , elemType : { kind : $ . TypeKind . Interface , methods : [ ] } } } ] , returns : [ ] } , { name : "scanComment" , args : [ ] , returns : [ { type : { kind : $ . TypeKind . Basic , name : "string" } } , { type : { kind : $ . TypeKind . Basic , name : "int" } } ] } , { name : "updateLineInfo" , args : [ { name : "next" , type : { kind : $ . TypeKind . Basic , name : "int" } } , { name : "offs" , type : { kind : $ . TypeKind . Basic , name : "int" } } , { name : "text" , type : { kind : $ . TypeKind . Slice , elemType : { kind : $ . TypeKind . Basic , name : "byte" } } } ] , returns : [ ] } , { name : "scanIdentifier" , args : [ ] , returns : [ { type : { kind : $ . TypeKind . Basic , name : "string" } } ] } , { name : "digits" , args : [ { name : "base" , type : { kind : $ . TypeKind . Basic , name : "int" } } , { name : "invalid" , type : { kind : $ . TypeKind . Pointer , elemType : { kind : $ . TypeKind . Basic , name : "int" } } } ] , returns : [ { type : { kind : $ . TypeKind . Basic , name : "int" } } ] } , { name : "scanNumber" , args : [ ] , returns : [ { type : "go/token.Token" } , { type : { kind : $ . TypeKind . Basic , name : "string" } } ] } , { name : "scanEscape" , args : [ { name : "quote" , type : { kind : $ . TypeKind . Basic , name : "rune" } } ] , returns : [ { type : { kind : $ . TypeKind . Basic , name : "bool" } } ] } , { name : "scanRune" , args : [ ] , returns : [ { type : { kind : $ . TypeKind . Basic , name : "string" } } ] } , { name : "scanString" , args : [ ] , returns : [ { type : { kind : $ . TypeKind . Basic , name : "string" } } ] } , { name : "scanRawString" , args : [ ] , returns : [ { type : { kind : $ . TypeKind . Basic , name : "string" } } , { type : { kind : $ . TypeKind . Basic , name : "int" } } ] } , { name : "skipWhitespace" , args : [ ] , returns : [ ] } , { name : "switch2" , args : [ { name : "tok0" , type : "go/token.Token" } , { name : "tok1" , type : "go/token.Token" } ] , returns : [ { type : "go/token.Token" } ] } , { name : "switch3" , args : [ { name : "tok0" , type : "go/token.Token" } , { name : "tok1" , type : "go/token.Token" } , { name : "ch2" , type : { kind : $ . TypeKind . Basic , name : "rune" } } , { name : "tok2" , type : "go/token.Token" } ] , returns : [ { type : "go/token.Token" } ] } , { name : "switch4" , args : [ { name : "tok0" , type : "go/token.Token" } , { name : "tok1" , type : "go/token.Token" } , { name : "ch2" , type : { kind : $ . TypeKind . Basic , name : "rune" } } , { name : "tok2" , type : "go/token.Token" } , { name : "tok3" , type : "go/token.Token" } ] , returns : [ { type : "go/token.Token" } ] } , { name : "Scan" , args : [ ] , returns : [ { type : "go/token.Pos" } , { type : "go/token.Token" } , { type : { kind : $ . TypeKind . Basic , name : "string" } } ] } ] ,
11231116 Scanner ,
1124- { "file" : { kind : $ . TypeKind . Pointer , elemType : "go/token.File" } , "dir" : { kind : $ . TypeKind . Basic , name : "string" } , "src" : { kind : $ . TypeKind . Slice , elemType : { kind : $ . TypeKind . Basic , name : "byte" } } , "err" : "go/scanner.ErrorHandler" , "mode" : "go/scanner.Mode" , "ch" : { kind : $ . TypeKind . Basic , name : "rune" } , "offset" : { kind : $ . TypeKind . Basic , name : "int" } , "rdOffset" : { kind : $ . TypeKind . Basic , name : "int" } , "lineOffset" : { kind : $ . TypeKind . Basic , name : "int" } , "insertSemi" : { kind : $ . TypeKind . Basic , name : "bool" } , "nlPos" : "go/token.Pos" , "endPosValid" : { kind : $ . TypeKind . Basic , name : "bool" } , "endPos " : "go/token.Pos" , "ErrorCount" : { kind : $ . TypeKind . Basic , name : "int" } }
1117+ { "file" : { kind : $ . TypeKind . Pointer , elemType : "go/token.File" } , "dir" : { kind : $ . TypeKind . Basic , name : "string" } , "src" : { kind : $ . TypeKind . Slice , elemType : { kind : $ . TypeKind . Basic , name : "byte" } } , "err" : "go/scanner.ErrorHandler" , "mode" : "go/scanner.Mode" , "ch" : { kind : $ . TypeKind . Basic , name : "rune" } , "offset" : { kind : $ . TypeKind . Basic , name : "int" } , "rdOffset" : { kind : $ . TypeKind . Basic , name : "int" } , "lineOffset" : { kind : $ . TypeKind . Basic , name : "int" } , "insertSemi" : { kind : $ . TypeKind . Basic , name : "bool" } , "nlPos" : "go/token.Pos" , "stringEnd " : "go/token.Pos" , "ErrorCount" : { kind : $ . TypeKind . Basic , name : "int" } }
11251118 ) ;
11261119}
11271120
11281121export let prefix : $ . Bytes = $ . stringToBytes ( "line " )
11291122
1123+ // Provide go/parser with backdoor access to the StringEnd information.
1124+ export function init ( ) : void {
1125+ scannerhooks . StringEnd = ( scanner : null | any ) : token . Pos => {
1126+ return $ . mustTypeAssert < Scanner | null > ( scanner , { kind : $ . TypeKind . Pointer , elemType : 'go/scanner.Scanner' } ) ! . stringEnd
1127+ }
1128+ }
1129+
11301130export function trailingDigits ( text : $ . Bytes ) : [ number , number , boolean ] {
11311131 let i = bytes . LastIndexByte ( text , 58 ) // look from right (Windows filenames may contain ':')
11321132
0 commit comments