z_mirror/luapls
git clone https://git.raiguard.me/z_mirror/luapls
8be9468
main
1package lexer 2 3import ( 4"strings" 5"unicode" 6"unicode/utf8" 7 8"github.com/raiguard/luapls/lua/token" 9) 10 11const digits string = "0123456789" 12const hexDigits string = digits + "abcdefABCDEF" 13const whitespace string = " \t\r\n" 14 15type Lexer struct { 16input string // the string being scanned. 17start int // start position of this token. 18pos int // current position in the input. 19width int // width of last rune read. 20 21lineBreaks []int 22} 23 24func New (input string )* Lexer { 25return & Lexer {input :input ,pos :0 ,lineBreaks : []int {}} 26} 27 28func (l * Lexer )Next () token.Token { 29l .ignore () 30 31if l .acceptRun (" \t" ) { 32return l .makeToken (token .WHITESPACE ) 33 } 34if l .acceptRun ("\r\n" ) { 35return l .makeToken (token .WHITESPACE ) 36 } 37 38tok := token .INVALID 39 40switch r := l .read ();r { 41case 0 :// EOF 42tok = token .EOF 43case '=' : 44if l .accept ("=" ) { 45tok = token .EQUAL 46 }else { 47tok = token .ASSIGN 48 } 49case '^' : 50tok = token .POW 51case '>' : 52if l .accept ("=" ) { 53tok = token .GEQ 54 }else { 55tok = token .GT 56 } 57case '<' : 58if l .accept ("=" ) { 59tok = token .LEQ 60 }else { 61tok = token .LT 62 } 63case '#' : 64tok = token .LEN 65case '-' : 66if l .accept ("-" ) { 67tok = token .COMMENT 68l .readComment () 69 }else { 70tok = token .MINUS 71 } 72case '%' : 73tok = token .MOD 74case '+' : 75tok = token .PLUS 76case '/' : 77tok = token .SLASH 78case '*' : 79tok = token .MUL 80case '~' : 81if l .accept ("=" ) { 82tok = token .NEQ 83 } 84case '(' : 85tok = token .LPAREN 86case ')' : 87tok = token .RPAREN 88case '[' : 89if l .readRawString () { 90tok = token .RAWSTRING 91 }else { 92tok = token .LBRACK 93 } 94case ']' : 95tok = token .RBRACK 96case '{' : 97tok = token .LBRACE 98case '}' : 99tok = token .RBRACE 100case ':' : 101if l .accept (":" ) { 102tok = token .LABEL 103 }else { 104tok = token .COLON 105 } 106case ',' : 107tok = token .COMMA 108case '.' : 109if l .accept ("." ) { 110if l .accept ("." ) { 111tok = token .VARARG 112 }else { 113tok = token .CONCAT 114 } 115 }else if unicode .IsDigit (l .peek ()) { 116l .backup () 117l .readNumber () 118tok = token .NUMBER 119 }else { 120tok = token .DOT 121 } 122case ';' : 123tok = token .SEMICOLON 124case '\'' ,'"' : 125if l .readString (r ) { 126tok = token .STRING 127 } 128case '@' : 129if l .readIdentifier () { 130if reserved ,ok := token .Reserved [l .input [l .start :l .pos ]];ok { 131tok = reserved 132 } 133 } 134default : 135if unicode .IsDigit (r ) { 136l .backup () 137if l .readNumber () { 138tok = token .NUMBER 139 }else { 140l .ignore () 141 } 142 }else if l .readIdentifier () { 143if reserved ,ok := token .Reserved [l .input [l .start :l .pos ]];ok { 144tok = reserved 145 }else { 146tok = token .IDENT 147 } 148 }else { 149// TODO: Make this unreachable 150l .read ()// Always make progress 151 } 152 } 153 154return l .makeToken (tok ) 155} 156 157func (l * Lexer )GetLineBreaks () []int { 158return l .lineBreaks 159} 160 161func Run (input string ) ([]token.Token , []int ) { 162l := New (input ) 163tokens := []token.Token {} 164for { 165tok := l .Next () 166tokens = append (tokens ,tok ) 167if tok .Type == token .EOF { 168break 169 } 170 } 171return tokens ,l .lineBreaks 172} 173 174func (l * Lexer )makeToken (typ token.TokenType ) token.Token { 175return token.Token { 176Type :typ , 177Literal :l .input [l .start :l .pos ], 178Pos :l .start , 179 } 180} 181 182// read returns the next rune in the input. 183func (l * Lexer )read () (r rune ) { 184if l .pos >= len (l .input ) { 185l .width = 0 186return 0 187 } 188r ,l .width = utf8 .DecodeRuneInString (l .input [l .pos :]) 189if r == '\n' && (len (l .lineBreaks )== 0 || l .lineBreaks [len (l .lineBreaks )- 1 ]!= l .pos ) { 190l .lineBreaks = append (l .lineBreaks ,l .pos ) 191 } 192l .pos += l .width 193return r 194} 195 196// ignore skips over the pending input before this point. 197func (l * Lexer )ignore () { 198l .start = l .pos 199} 200 201// backup steps back one rune. 202// Can only be called once per call of next. 203func (l * Lexer )backup () { 204l .pos -= l .width 205} 206 207// peek returns but does not consume the next rune in the input. 208func (l * Lexer )peek ()rune { 209rune := l .read () 210l .backup () 211return rune 212} 213 214// accept consumes the next rune if it is from the valid set. 215func (l * Lexer )accept (valid string )bool { 216if strings .IndexRune (valid ,l .read ())>= 0 { 217return true 218 } 219l .backup () 220return false 221} 222 223// acceptRun accepts a run of runes from the valid set. 224func (l * Lexer )acceptRun (valid string )bool { 225success := false 226for l .accept (valid ) { 227success = true 228 } 229return success 230} 231 232// acceptNot consumes the next rune if it is from the valid set. 233func (l * Lexer )acceptNot (valid string )bool { 234r := l .read () 235if r != 0 && strings .IndexRune (valid ,r )== - 1 { 236return true 237 } 238l .backup () 239return false 240} 241 242// acceptNotRun acceptNots a run of runes from the valid set. 243func (l * Lexer )acceptNotRun (valid string ) { 244for l .acceptNot (valid ) { 245 } 246} 247 248// TODO: Type annotations 249func (l * Lexer )readComment () { 250if l .accept ("[" )&& l .readRawString () { 251return 252 } 253for l .acceptNot ("\n" ) { 254 } 255return 256} 257 258func (l * Lexer )readNumber ()bool { 259useDigits := digits 260if l .accept ("0" )&& l .accept ("xX" ) { 261useDigits = hexDigits 262 } 263l .acceptRun (useDigits ) 264 265if l .accept ("." ) { 266l .acceptRun (useDigits ) 267 } 268 269if l .accept ("eE" ) { 270l .acceptRun (digits ) 271l .accept ("+-" ) 272l .acceptRun (digits ) 273 }else if l .accept ("pP" ) { 274l .acceptRun (hexDigits ) 275l .accept ("+-" ) 276l .acceptRun (hexDigits ) 277 } 278 279return true 280} 281 282func (l * Lexer )readIdentifier ()bool { 283for isIdentifier (l .read ()) { 284 } 285l .backup () 286return true 287} 288 289func (l * Lexer )readString (quote rune )bool { 290for { 291if l .accept (string (quote )) { 292break 293 } 294if l .accept ("\n" )|| l .peek ()== 0 { 295// TODO: Lexing error 296return false 297 } 298if l .accept ("\\" ) { 299if l .accept ("z" ) { 300l .acceptRun (whitespace ) 301continue 302 } 303if l .accept (string (quote ))|| l .accept ("abfnrtvz\r\n" ) { 304continue 305 } 306 } 307l .read () 308 } 309return true 310} 311 312func (l * Lexer )readRawString ()bool { 313if ! l .accept ("[=" ) { 314return false 315 } 316l .backup () 317level := 0 318for l .accept ("=" ) { 319level ++ 320 } 321if ! l .accept ("[" ) { 322return false 323 } 324for { 325l .acceptNotRun ("]" ) 326if ! l .accept ("]" ) { 327return false 328 } 329thisLevel := 0 330for l .accept ("=" ) { 331thisLevel ++ 332 } 333if ! l .accept ("]" ) { 334continue 335 } 336if thisLevel == level { 337break 338 } 339l .backup () 340 } 341return true 342} 343 344func isIdentifier (rune rune )bool { 345return unicode .IsLetter (rune )|| unicode .IsDigit (rune )|| rune == '_' 346}