scanner.v: refactoring
parent
8462e99bc5
commit
88758082d2
1
Makefile
1
Makefile
|
@ -25,6 +25,7 @@ test: v
|
|||
|
||||
clean:
|
||||
-rm -f v.c .v.c v vprod thirdparty/**/*.o
|
||||
find . -name '.*.c' -print0 | xargs -0 -n1 rm -f
|
||||
|
||||
SOURCES = $(wildcard thirdparty/**/*.c)
|
||||
OBJECTS := ${SOURCES:.c=.o}
|
||||
|
|
|
@ -823,7 +823,7 @@ fn (p mut Parser) get_type() string {
|
|||
if p.tok == .lsbr {
|
||||
p.check(.lsbr)
|
||||
// [10]int
|
||||
if p.tok == .integer {
|
||||
if p.tok == .number {
|
||||
typ = '[$p.lit]'
|
||||
p.next()
|
||||
}
|
||||
|
@ -834,9 +834,9 @@ fn (p mut Parser) get_type() string {
|
|||
// [10][3]int
|
||||
if p.tok == .lsbr {
|
||||
p.next()
|
||||
if p.tok == .integer {
|
||||
if p.tok == .number {
|
||||
typ += '[$p.lit]'
|
||||
p.check(.integer)
|
||||
p.check(.number)
|
||||
}
|
||||
else {
|
||||
is_arr2 = true
|
||||
|
@ -2095,7 +2095,7 @@ fn (p mut Parser) term() string {
|
|||
p.next()
|
||||
p.gen(tok.str())// + ' /*op2*/ ')
|
||||
p.fgen(' ' + tok.str() + ' ')
|
||||
if is_div && p.tok == .integer && p.lit == '0' {
|
||||
if is_div && p.tok == .number && p.lit == '0' {
|
||||
p.error('division by zero')
|
||||
}
|
||||
if is_mod && (is_float_type(typ) || !is_number_type(typ)) {
|
||||
|
@ -2129,7 +2129,7 @@ fn (p mut Parser) factor() string {
|
|||
mut typ := ''
|
||||
tok := p.tok
|
||||
switch tok {
|
||||
case .integer:
|
||||
case .number:
|
||||
typ = 'int'
|
||||
// Check if float (`1.0`, `1e+3`) but not if is hexa
|
||||
if (p.lit.contains('.') || (p.lit.contains('e') || p.lit.contains('E'))) &&
|
||||
|
@ -2452,7 +2452,7 @@ fn (p mut Parser) map_init() string {
|
|||
fn (p mut Parser) array_init() string {
|
||||
p.is_alloc = true
|
||||
p.check(.lsbr)
|
||||
is_integer := p.tok == .integer
|
||||
is_integer := p.tok == .number
|
||||
lit := p.lit
|
||||
mut typ := ''
|
||||
new_arr_ph := p.cgen.add_placeholder()
|
||||
|
@ -3334,7 +3334,7 @@ fn (p mut Parser) return_st() {
|
|||
}
|
||||
else {
|
||||
// Don't allow `return val` in functions that don't return anything
|
||||
if false && p.tok == .name || p.tok == .integer {
|
||||
if false && p.tok == .name || p.tok == .number {
|
||||
p.error('function `$p.cur_fn.name` does not return a value')
|
||||
}
|
||||
|
||||
|
@ -3529,3 +3529,16 @@ fn (p mut Parser) fspace() {
|
|||
fn (p mut Parser) fgenln(s string) {
|
||||
p.scanner.fgenln(s)
|
||||
}
|
||||
|
||||
fn (p mut Parser) peek() Token {
|
||||
for {
|
||||
tok := p.scanner.peek()
|
||||
if tok != .nl {
|
||||
return tok
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn (p mut Parser) create_type_string(T Type, name string) {
|
||||
p.scanner.create_type_string(T, name)
|
||||
}
|
||||
|
|
|
@ -26,16 +26,11 @@ mut:
|
|||
prev_tok Token
|
||||
}
|
||||
|
||||
const (
|
||||
SingleQuote = `\'`
|
||||
//QUOTE = `"`
|
||||
)
|
||||
|
||||
fn new_scanner(file_path string) *Scanner {
|
||||
if !os.file_exists(file_path) {
|
||||
panic('"$file_path" doesn\'t exist')
|
||||
}
|
||||
//text := os.read_file(file_path)
|
||||
|
||||
mut raw_text := os.read_file(file_path) or {
|
||||
panic('scanner: failed to open "$file_path"')
|
||||
return &Scanner{}
|
||||
|
@ -60,7 +55,6 @@ fn new_scanner(file_path string) *Scanner {
|
|||
fmt_out: strings.new_builder(1000)
|
||||
}
|
||||
|
||||
// println('new scanner "$file_path" txt.len=$scanner.text.len')
|
||||
return scanner
|
||||
}
|
||||
|
||||
|
@ -74,14 +68,6 @@ fn scan_res(tok Token, lit string) ScanRes {
|
|||
return ScanRes{tok, lit}
|
||||
}
|
||||
|
||||
fn is_white(c byte) bool {
|
||||
return c.is_white()
|
||||
}
|
||||
|
||||
fn is_nl(c byte) bool {
|
||||
return c == `\r` || c == `\n`
|
||||
}
|
||||
|
||||
fn (s mut Scanner) ident_name() string {
|
||||
start := s.pos
|
||||
for {
|
||||
|
@ -99,51 +85,119 @@ fn (s mut Scanner) ident_name() string {
|
|||
return name
|
||||
}
|
||||
|
||||
fn (s mut Scanner) ident_number() string {
|
||||
start := s.pos
|
||||
is_hex := s.pos + 1 < s.text.len && s.text[s.pos] == `0` && s.text[s.pos + 1] == `x`
|
||||
is_oct := !is_hex && s.text[s.pos] == `0`
|
||||
mut is_float := false
|
||||
fn (s mut Scanner) ident_hex_number() string {
|
||||
start_pos := s.pos
|
||||
s.pos += 2 // skip '0x'
|
||||
for {
|
||||
s.pos++
|
||||
if s.pos >= s.text.len {
|
||||
break
|
||||
}
|
||||
c := s.text[s.pos]
|
||||
if c == `.` {
|
||||
is_float = true
|
||||
}
|
||||
is_good_hex := is_hex && (c == `x` || (c >= `a` && c <= `f`) || (c >= `A` && c <= `F`))
|
||||
// 1e+3, 1e-3, 1e3
|
||||
if !is_hex && c == `e` && s.pos + 1 < s.text.len {
|
||||
next := s.text[s.pos + 1]
|
||||
if next == `+` || next == `-` || next.is_digit() {
|
||||
s.pos++
|
||||
continue
|
||||
}
|
||||
}
|
||||
if !c.is_digit() && c != `.` && !is_good_hex {
|
||||
if !c.is_hex_digit() {
|
||||
break
|
||||
}
|
||||
// 1..9
|
||||
if c == `.` && s.pos + 1 < s.text.len && s.text[s.pos + 1] == `.` {
|
||||
break
|
||||
}
|
||||
if is_oct && c >= `8` && !is_float {
|
||||
s.error('malformed octal constant')
|
||||
}
|
||||
s.pos++
|
||||
}
|
||||
number := s.text.substr(start, s.pos)
|
||||
number := s.text.substr(start_pos, s.pos)
|
||||
s.pos--
|
||||
return number
|
||||
}
|
||||
|
||||
fn (s mut Scanner) ident_oct_number() string {
|
||||
start_pos := s.pos
|
||||
for {
|
||||
if s.pos >= s.text.len {
|
||||
break
|
||||
}
|
||||
c := s.text[s.pos]
|
||||
if c.is_digit() {
|
||||
if !c.is_oct_digit() {
|
||||
s.error('malformed octal constant')
|
||||
}
|
||||
} else {
|
||||
break
|
||||
}
|
||||
s.pos++
|
||||
}
|
||||
number := s.text.substr(start_pos, s.pos)
|
||||
s.pos--
|
||||
return number
|
||||
}
|
||||
|
||||
fn (s mut Scanner) ident_dec_number() string {
|
||||
start_pos := s.pos
|
||||
|
||||
// scan integer part
|
||||
for s.text[s.pos].is_digit() {
|
||||
s.pos++
|
||||
}
|
||||
|
||||
// e.g. 1..9
|
||||
// we just return '1' and don't scan '..9'
|
||||
if s.expect('..', s.pos) {
|
||||
number := s.text.substr(start_pos, s.pos)
|
||||
s.pos--
|
||||
return number
|
||||
}
|
||||
|
||||
// scan fractional part
|
||||
if s.text[s.pos] == `.` {
|
||||
s.pos++
|
||||
for s.text[s.pos].is_digit() {
|
||||
s.pos++
|
||||
}
|
||||
}
|
||||
|
||||
// scan exponential part
|
||||
mut has_exponential_part := false
|
||||
if s.expect('e+', s.pos) || s.expect('e-', s.pos) {
|
||||
exp_start_pos := s.pos += 2
|
||||
for s.text[s.pos].is_digit() {
|
||||
s.pos++
|
||||
}
|
||||
if exp_start_pos == s.pos {
|
||||
s.error('exponent has no digits')
|
||||
}
|
||||
has_exponential_part = true
|
||||
}
|
||||
|
||||
// error check: 1.23.4, 123.e+3.4
|
||||
if s.text[s.pos] == `.` {
|
||||
if has_exponential_part {
|
||||
s.error('exponential part should be integer')
|
||||
}
|
||||
else {
|
||||
s.error('too many decimal points in number')
|
||||
}
|
||||
}
|
||||
|
||||
number := s.text.substr(start_pos, s.pos)
|
||||
s.pos--
|
||||
return number
|
||||
}
|
||||
|
||||
fn (s mut Scanner) ident_number() string {
|
||||
if s.expect('0x', s.pos) {
|
||||
return s.ident_hex_number()
|
||||
}
|
||||
|
||||
if s.expect('0.', s.pos) || s.expect('0e', s.pos) {
|
||||
return s.ident_dec_number()
|
||||
}
|
||||
|
||||
if s.text[s.pos] == `0` {
|
||||
return s.ident_oct_number()
|
||||
}
|
||||
|
||||
return s.ident_dec_number()
|
||||
}
|
||||
|
||||
fn (s Scanner) has_gone_over_line_end() bool {
|
||||
mut i := s.pos-1
|
||||
for i >= 0 && !is_white(s.text[i]) {
|
||||
for i >= 0 && !s.text[i].is_white() {
|
||||
i--
|
||||
}
|
||||
for i >= 0 && is_white(s.text[i]) {
|
||||
for i >= 0 && s.text[i].is_white() {
|
||||
if is_nl(s.text[i]) {
|
||||
return true
|
||||
}
|
||||
|
@ -153,45 +207,21 @@ fn (s Scanner) has_gone_over_line_end() bool {
|
|||
}
|
||||
|
||||
fn (s mut Scanner) skip_whitespace() {
|
||||
for s.pos < s.text.len && is_white(s.text[s.pos]) {
|
||||
if is_nl(s.text[s.pos]) {
|
||||
// Count \r\n as one line
|
||||
if !(s.text[s.pos] == `\n` && s.pos > 0 && s.text[s.pos-1] == `\r`) {
|
||||
for s.pos < s.text.len && s.text[s.pos].is_white() {
|
||||
// Count \r\n as one line
|
||||
if is_nl(s.text[s.pos]) && !s.expect('\r\n', s.pos-1) {
|
||||
s.line_nr++
|
||||
}
|
||||
}
|
||||
s.pos++
|
||||
}
|
||||
// if s.pos == s.text.len {
|
||||
// return scan_res(.eof, '')
|
||||
// }
|
||||
}
|
||||
|
||||
fn (s mut Scanner) get_var_name(pos int) string {
|
||||
mut pos_start := pos
|
||||
|
||||
for ; pos_start >= 0 && s.text[pos_start] != `\n` && s.text[pos_start] != `;`; pos_start-- {}
|
||||
pos_start++
|
||||
return s.text.substr(pos_start, pos)
|
||||
}
|
||||
|
||||
// CAO stands for Compound Assignment Operators (e.g '+=' )
|
||||
/*
|
||||
fn (s mut Scanner) cao_change(operator string) {
|
||||
s.text = s.text.substr(0, s.pos - operator.len) + ' = ' + s.get_var_name(s.pos - operator.len) + ' ' + operator + ' ' + s.text.substr(s.pos + 1, s.text.len)
|
||||
}
|
||||
*/
|
||||
|
||||
fn (s mut Scanner) scan() ScanRes {
|
||||
if s.line_comment != '' {
|
||||
//s.fgenln('// LOL "$s.line_comment"')
|
||||
//s.line_comment = ''
|
||||
}
|
||||
// if s.file_path == 'd.v' {
|
||||
// println('\nscan()')
|
||||
// }
|
||||
if s.line_comment != '' {
|
||||
//s.fgenln('// LOL "$s.line_comment"')
|
||||
//s.line_comment = ''
|
||||
}
|
||||
if s.started {
|
||||
// || (s.pos == 0 && s.text.len > 0 && s.text[s.pos] == `\n`) {
|
||||
s.pos++
|
||||
}
|
||||
s.started = true
|
||||
|
@ -204,8 +234,7 @@ if s.line_comment != '' {
|
|||
}
|
||||
// End of $var, start next string
|
||||
if s.dollar_end {
|
||||
// fmt.Println("end of $var, get string", s.pos, string(s.text[s.pos]))
|
||||
if s.text[s.pos] == SingleQuote {
|
||||
if s.text[s.pos] == `\'` {
|
||||
s.dollar_end = false
|
||||
return scan_res(.str, '')
|
||||
}
|
||||
|
@ -215,7 +244,6 @@ if s.line_comment != '' {
|
|||
s.skip_whitespace()
|
||||
// end of file
|
||||
if s.pos >= s.text.len {
|
||||
// println('scan(): returning .eof (pos >= len)')
|
||||
return scan_res(.eof, '')
|
||||
}
|
||||
// handle each char
|
||||
|
@ -230,26 +258,19 @@ if s.line_comment != '' {
|
|||
// tmp hack to detect . in ${}
|
||||
// Check if not .eof to prevent panic
|
||||
next_char := if s.pos + 1 < s.text.len { s.text[s.pos + 1] } else { `\0` }
|
||||
// println('!!! got name=$name next_char=$next_char')
|
||||
if is_key(name) {
|
||||
// println('IS KEY')
|
||||
// tok := (key_to_token(name))
|
||||
// println(tok.str())
|
||||
return scan_res(key_to_token(name), '')
|
||||
}
|
||||
// 'asdf $b' => "b" is the last name in the string, dont start parsing string
|
||||
// at the next ', skip it
|
||||
if s.inside_string {
|
||||
// println('is_letter inside string! nextc=${nextc.str()}')
|
||||
if next_char == SingleQuote {
|
||||
// println('var is last before QUOTE')
|
||||
if next_char == `\'` {
|
||||
s.pos++
|
||||
s.dollar_start = false
|
||||
s.inside_string = false
|
||||
}
|
||||
}
|
||||
if s.dollar_start && next_char != `.` {//&& next_char != `(` {
|
||||
// println('INSIDE .str .dollar var=$name')
|
||||
if s.dollar_start && next_char != `.` {
|
||||
s.dollar_end = true
|
||||
s.dollar_start = false
|
||||
}
|
||||
|
@ -263,7 +284,7 @@ if s.line_comment != '' {
|
|||
// `123`, `.123`
|
||||
else if c.is_digit() || c == `.` && nextc.is_digit() {
|
||||
num := s.ident_number()
|
||||
return scan_res(.integer, num)
|
||||
return scan_res(.number, num)
|
||||
}
|
||||
// all other tokens
|
||||
switch c {
|
||||
|
@ -307,7 +328,7 @@ if s.line_comment != '' {
|
|||
return scan_res(.mod, '')
|
||||
case `?`:
|
||||
return scan_res(.question, '')
|
||||
case SingleQuote:
|
||||
case `\'`:
|
||||
return scan_res(.str, s.ident_string())
|
||||
// TODO allow double quotes
|
||||
// case QUOTE:
|
||||
|
@ -336,7 +357,7 @@ if s.line_comment != '' {
|
|||
if s.inside_string {
|
||||
s.pos++
|
||||
// TODO UN.neEDED?
|
||||
if s.text[s.pos] == SingleQuote {
|
||||
if s.text[s.pos] == `\'` {
|
||||
s.inside_string = false
|
||||
return scan_res(.str, '')
|
||||
}
|
||||
|
@ -458,7 +479,6 @@ if s.line_comment != '' {
|
|||
return scan_res(.div_assign, '')
|
||||
}
|
||||
if nextc == `/` {
|
||||
// debug("!!!!!!.key_goT LI.ne COM")
|
||||
start := s.pos + 1
|
||||
for s.pos < s.text.len && s.text[s.pos] != `\n`{
|
||||
s.pos++
|
||||
|
@ -485,11 +505,11 @@ if s.line_comment != '' {
|
|||
s.line_nr++
|
||||
continue
|
||||
}
|
||||
if s.text[s.pos] == `/` && s.text[s.pos + 1] == `*` {
|
||||
if s.expect('/*', s.pos) {
|
||||
nest_count++
|
||||
continue
|
||||
}
|
||||
if s.text[s.pos] == `*` && s.text[s.pos + 1] == `/` {
|
||||
if s.expect('*/', s.pos) {
|
||||
nest_count--
|
||||
}
|
||||
}
|
||||
|
@ -507,7 +527,6 @@ if s.line_comment != '' {
|
|||
return scan_res(.eof, '')
|
||||
}
|
||||
}
|
||||
println('(char code=$c) pos=$s.pos len=$s.text.len')
|
||||
mut msg := 'invalid character `${c.str()}`'
|
||||
if c == `"` {
|
||||
msg += ', use \' to denote strings'
|
||||
|
@ -520,9 +539,6 @@ fn (s &Scanner) error(msg string) {
|
|||
file := s.file_path.all_after('/')
|
||||
println('panic: $file:${s.line_nr + 1}')
|
||||
println(msg)
|
||||
// os.print_backtrace()
|
||||
// println(file)
|
||||
// println(s.file_path)
|
||||
exit(1)
|
||||
}
|
||||
|
||||
|
@ -531,10 +547,6 @@ fn (s &Scanner) error(msg string) {
|
|||
fn (s mut Scanner) ident_string() string {
|
||||
// println("\nidentString() at char=", string(s.text[s.pos]),
|
||||
// "chard=", s.text[s.pos], " pos=", s.pos, "txt=", s.text[s.pos:s.pos+7])
|
||||
debug := s.file_path.contains('test_test')
|
||||
if debug {
|
||||
println('identStr() $s.file_path line=$s.line_nr pos=$s.pos')
|
||||
}
|
||||
mut start := s.pos
|
||||
s.inside_string = false
|
||||
slash := `\\`
|
||||
|
@ -544,12 +556,9 @@ fn (s mut Scanner) ident_string() string {
|
|||
break
|
||||
}
|
||||
c := s.text[s.pos]
|
||||
if debug {
|
||||
println(c.str())
|
||||
}
|
||||
prevc := s.text[s.pos - 1]
|
||||
// end of string
|
||||
if c == SingleQuote && (prevc != slash || (prevc == slash && s.text[s.pos - 2] == slash)) {
|
||||
if c == `\'` && (prevc != slash || (prevc == slash && s.text[s.pos - 2] == slash)) {
|
||||
// handle '123\\' slash at the end
|
||||
break
|
||||
}
|
||||
|
@ -561,8 +570,7 @@ fn (s mut Scanner) ident_string() string {
|
|||
s.error('0 character in a string literal')
|
||||
}
|
||||
// Don't allow \x00
|
||||
if c == `0` && s.pos > 5 && s.text[s.pos - 1] == `0` && s.text[s.pos - 2] == `x` &&
|
||||
s.text[s.pos - 3] == `\\` {
|
||||
if c == `0` && s.pos > 5 && s.expect('\\x0', s.pos - 3) {
|
||||
s.error('0 character in a string literal')
|
||||
}
|
||||
// ${var}
|
||||
|
@ -573,17 +581,15 @@ fn (s mut Scanner) ident_string() string {
|
|||
break
|
||||
}
|
||||
// $var
|
||||
// if !s.is_fmt && c != `{` && c != ` ` && ! (c >= `0` && c <= `9`) && prevc == `$` {
|
||||
if (c.is_letter() || c == `_`) && prevc == `$` {
|
||||
s.inside_string = true
|
||||
s.dollar_start = true
|
||||
// println('setting s.dollar=true pos=$s.pos')
|
||||
s.pos -= 2
|
||||
break
|
||||
}
|
||||
}
|
||||
mut lit := ''
|
||||
if s.text[start] == SingleQuote {
|
||||
if s.text[start] == `\'` {
|
||||
start++
|
||||
}
|
||||
mut end := s.pos
|
||||
|
@ -594,17 +600,6 @@ fn (s mut Scanner) ident_string() string {
|
|||
else {
|
||||
lit = s.text.substr(start, end)
|
||||
}
|
||||
// if lit.contains('\n') {
|
||||
// println('\nstring lit="$lit" pos=$s.pos line=$s.line_nr')
|
||||
// }
|
||||
/*
|
||||
for c in lit {
|
||||
if s.file_path.contains('range_test') {
|
||||
println('!')
|
||||
println(c)
|
||||
}
|
||||
}
|
||||
*/
|
||||
return lit
|
||||
}
|
||||
|
||||
|
@ -620,7 +615,7 @@ fn (s mut Scanner) ident_char() string {
|
|||
if s.text[s.pos] != slash {
|
||||
len++
|
||||
}
|
||||
double_slash := s.text[s.pos - 1] == slash && s.text[s.pos - 2] == slash
|
||||
double_slash := s.expect('\\\\', s.pos - 2)
|
||||
if s.text[s.pos] == `\`` && (s.text[s.pos - 1] != slash || double_slash) {
|
||||
if double_slash {
|
||||
len++
|
||||
|
@ -633,30 +628,24 @@ fn (s mut Scanner) ident_char() string {
|
|||
if len != 1 {
|
||||
u := c.ustring()
|
||||
if u.len != 1 {
|
||||
s.error('invalid character literal (more than one character: $len)')
|
||||
s.error('invalid character literal (more than one character: $len)')
|
||||
}
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
fn (p mut Parser) peek() Token {
|
||||
for {
|
||||
tok := p.scanner.peek()
|
||||
if tok != .nl {
|
||||
return tok
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn (s mut Scanner) peek() Token {
|
||||
// save scanner state
|
||||
pos := s.pos
|
||||
line := s.line_nr
|
||||
inside_string := s.inside_string
|
||||
dollar_start := s.dollar_start
|
||||
dollar_end := s.dollar_end
|
||||
// /////
|
||||
|
||||
res := s.scan()
|
||||
tok := res.tok
|
||||
|
||||
// restore scanner state
|
||||
s.pos = pos
|
||||
s.line_nr = line
|
||||
s.inside_string = inside_string
|
||||
|
@ -665,30 +654,42 @@ fn (s mut Scanner) peek() Token {
|
|||
return tok
|
||||
}
|
||||
|
||||
fn (s mut Scanner) expect(want string, start_pos int) bool {
|
||||
end_pos := start_pos + want.len
|
||||
if start_pos < 0 || start_pos >= s.text.len {
|
||||
return false
|
||||
}
|
||||
if end_pos < 0 || end_pos > s.text.len {
|
||||
return false
|
||||
}
|
||||
for pos in start_pos..end_pos {
|
||||
if s.text[pos] != want[pos-start_pos] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
fn (s mut Scanner) debug_tokens() {
|
||||
s.pos = 0
|
||||
s.debug = true
|
||||
|
||||
fname := s.file_path.all_after('/')
|
||||
println('\n===DEBUG TOKENS $fname===')
|
||||
// allToks := ''
|
||||
s.debug = true
|
||||
|
||||
for {
|
||||
res := s.scan()
|
||||
tok := res.tok
|
||||
lit := res.lit
|
||||
// printiln(tok)
|
||||
print(tok.str())
|
||||
// allToks += tok.String()
|
||||
if lit != '' {
|
||||
println(' `$lit`')
|
||||
// allToks += " `" + lit + "`"
|
||||
}
|
||||
else {
|
||||
println('')
|
||||
}
|
||||
// allToks += "\n"
|
||||
if tok == .eof {
|
||||
println('============ END OF DEBUG TOKENS ==================')
|
||||
// fmt.Println("========"+s.file+"========\n", allToks)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
@ -698,6 +699,10 @@ fn is_name_char(c byte) bool {
|
|||
return c.is_letter() || c == `_`
|
||||
}
|
||||
|
||||
fn is_nl(c byte) bool {
|
||||
return c == `\r` || c == `\n`
|
||||
}
|
||||
|
||||
fn (s mut Scanner) get_opening_bracket() int {
|
||||
mut pos := s.pos
|
||||
mut parentheses := 0
|
||||
|
@ -740,7 +745,3 @@ fn (s mut Scanner) create_type_string(T Type, name string) {
|
|||
s.line_nr = line
|
||||
s.inside_string = inside_string
|
||||
}
|
||||
|
||||
fn (p mut Parser) create_type_string(T Type, name string) {
|
||||
p.scanner.create_type_string(T, name)
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ module main
|
|||
enum Token {
|
||||
eof
|
||||
name // user
|
||||
integer // 123
|
||||
number // 123
|
||||
str // 'foo'
|
||||
str_inter // 'name=$user.name'
|
||||
chartoken // `A`
|
||||
|
@ -127,7 +127,7 @@ fn build_token_str() []string {
|
|||
s[Token.keyword_end] = ''
|
||||
s[Token.eof] = '.eof'
|
||||
s[Token.name] = '.name'
|
||||
s[Token.integer] = '.integer'
|
||||
s[Token.number] = '.number'
|
||||
s[Token.str] = 'STR'
|
||||
s[Token.chartoken] = '.chartoken'
|
||||
s[Token.plus] = '+'
|
||||
|
|
|
@ -714,6 +714,14 @@ pub fn (c byte) is_digit() bool {
|
|||
return c >= `0` && c <= `9`
|
||||
}
|
||||
|
||||
pub fn (c byte) is_hex_digit() bool {
|
||||
return c.is_digit() || (c >= `a` && c <= `f`) || (c >= `A` && c <= `F`)
|
||||
}
|
||||
|
||||
pub fn (c byte) is_oct_digit() bool {
|
||||
return c >= `0` && c <= `7`
|
||||
}
|
||||
|
||||
pub fn (c byte) is_letter() bool {
|
||||
return (c >= `a` && c <= `z`) || (c >= `A` && c <= `Z`)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue