From c915c58d12f2d7f58ce39f1d6ff9e48182778b3a Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Sun, 29 Dec 2019 06:50:08 +0100 Subject: [PATCH] local vars + Parser.errror() --- Makefile | 6 +- vlib/v/cgen/cgen_test.v | 3 +- vlib/v/cgen/tests/2.c | 2 + vlib/v/cgen/tests/2.v | 5 +- vlib/v/parser/parser.v | 27 ++++++- vlib/v/scanner/scanner.v | 154 +++++++++++++++++++-------------------- vlib/v/table/table.v | 60 ++++++++++++++- vlib/v/token/token.v | 6 +- 8 files changed, 173 insertions(+), 90 deletions(-) diff --git a/Makefile b/Makefile index 1378818655..80ef5f4668 100644 --- a/Makefile +++ b/Makefile @@ -93,8 +93,8 @@ selfcompile: modules: module_builtin module_strings module_strconv module_builtin: - ./v build module vlib/builtin > /dev/null + #./v build module vlib/builtin > /dev/null module_strings: - ./v build module vlib/strings > /dev/null + #./v build module vlib/strings > /dev/null module_strconv: - ./v build module vlib/strconv > /dev/null + #./v build module vlib/strconv > /dev/null diff --git a/vlib/v/cgen/cgen_test.v b/vlib/v/cgen/cgen_test.v index 994079343a..acca534c98 100644 --- a/vlib/v/cgen/cgen_test.v +++ b/vlib/v/cgen/cgen_test.v @@ -5,6 +5,7 @@ import ( v.ast v.cgen v.table + term ) const ( @@ -29,7 +30,7 @@ fn test_c_files() { eprintln('${i}... OK') } else { - eprintln('${i}... FAIL') + eprintln('${i}... ' + term.red('FAIL')) eprintln('expected:\n$ctext\ngot:\n$res') } } diff --git a/vlib/v/cgen/tests/2.c b/vlib/v/cgen/tests/2.c index 855757c610..ee380abf45 100644 --- a/vlib/v/cgen/tests/2.c +++ b/vlib/v/cgen/tests/2.c @@ -10,4 +10,6 @@ void function2() { string s = tos3("hi"); int m = 10; x += 10; + x += 1; + m += 2; } diff --git a/vlib/v/cgen/tests/2.v b/vlib/v/cgen/tests/2.v index 44cc7baeb0..123c1fd5e4 100644 --- a/vlib/v/cgen/tests/2.v +++ b/vlib/v/cgen/tests/2.v @@ -9,7 +9,10 @@ fn function2() { mut x := 0 f := 10.1 s := 'hi' - m := 10 + mut m := 10 x += 10 + x += 1 + m += 2 + //a += 1 //c := 0 } diff --git a/vlib/v/parser/parser.v b/vlib/v/parser/parser.v index 581bed9778..9ff59eb5d8 100644 --- a/vlib/v/parser/parser.v +++ b/vlib/v/parser/parser.v @@ -9,6 +9,7 @@ import ( v.token v.table v.types + term ) struct Parser { @@ -169,9 +170,18 @@ pub fn (p mut Parser) stmt() ast.Stmt { } pub fn (p mut Parser) assign_stmt() ast.AssignStmt { + name := p.tok.lit + //println('looking for $name') + var := p.table.find_var(name) or { + p.error('unknown variable `$name`') + exit(1) + } + if !var.is_mut { + p.error('`$var.name` is immutable, declare it with `mut $var.name := ...`') + } left_expr,left_type := p.expr(0) op := p.tok.kind - println('assignn_stmt() ' + op.str()) + //println('assignn_stmt() ' + op.str()) p.next() right_expr,right_type := p.expr(0) return ast.AssignStmt{ @@ -181,6 +191,11 @@ pub fn (p mut Parser) assign_stmt() ast.AssignStmt { } } +pub fn (p &Parser) error(s string) { + println(term.bold(term.red('x.v:$p.tok.line_nr: $s'))) + exit(1) +} + // Implementation of Pratt Precedence pub fn (p mut Parser) expr(rbp int) (ast.Expr,types.Type) { // println('expr at ' + p.tok.str()) @@ -295,6 +310,7 @@ fn (p mut Parser) import_stmt() ast.Import { } fn (p mut Parser) fn_decl() ast.FnDecl { + p.table.clear_vars() p.check(.key_fn) name := p.tok.lit // println('fn decl $name') @@ -343,16 +359,19 @@ fn (p mut Parser) var_decl() ast.VarDecl { name := p.tok.lit p.read_first_token() expr,t := p.expr(token.lowest_prec) - if name in p.table.names { + if _ := p.table.find_var(name) { verror('redefinition of `$name`') } - p.table.names << name + p.table.register_var(table.Var{ + name: name + is_mut: is_mut + }) // println(p.table.names) // println('added $name') return ast.VarDecl{ name: name expr: expr // p.expr(token.lowest_prec) - + typ: t } } diff --git a/vlib/v/scanner/scanner.v b/vlib/v/scanner/scanner.v index 95a590fd83..c4f71c7b7a 100644 --- a/vlib/v/scanner/scanner.v +++ b/vlib/v/scanner/scanner.v @@ -75,9 +75,9 @@ pub fn new_scanner(text string) &Scanner { } } -fn scan_res(tok token.TokenKind, lit string) token.Token { +fn (s &Scanner) scan_res(tok token.TokenKind, lit string) token.Token { return token.Token{ - tok,lit} + tok,lit,s.line_nr + 1} } fn (s mut Scanner) ident_name() string { @@ -216,7 +216,7 @@ fn (s mut Scanner) skip_whitespace() { fn (s mut Scanner) end_of_file() token.Token { s.pos = s.text.len s.inc_line_number() - return scan_res(.eof, '') + return s.scan_res(.eof, '') } pub fn (s mut Scanner) scan() token.Token { @@ -238,10 +238,10 @@ pub fn (s mut Scanner) scan() token.Token { if s.inter_end { if s.text[s.pos] == s.quote { s.inter_end = false - return scan_res(.str, '') + return s.scan_res(.str, '') } s.inter_end = false - return scan_res(.str, s.ident_string()) + return s.scan_res(.str, s.ident_string()) } s.skip_whitespace() // end of file @@ -261,7 +261,7 @@ pub fn (s mut Scanner) scan() token.Token { // Check if not .eof to prevent panic next_char := if s.pos + 1 < s.text.len { s.text[s.pos + 1] } else { `\0` } if token.is_key(name) { - return scan_res(token.key_to_token(name), '') + return s.scan_res(token.key_to_token(name), '') } // 'asdf $b' => "b" is the last name in the string, dont start parsing string // at the next ', skip it @@ -283,12 +283,12 @@ pub fn (s mut Scanner) scan() token.Token { // Otherwise the scanner would be stuck at s.pos = 0 s.pos++ } - return scan_res(.name, name) + return s.scan_res(.name, name) } // `123`, `.123` else if c.is_digit() || (c == `.` && nextc.is_digit()) { num := s.ident_number() - return scan_res(.number, num) + return s.scan_res(.number, num) } // Handle `'$fn()'` if c == `)` && s.inter_start { @@ -298,88 +298,88 @@ pub fn (s mut Scanner) scan() token.Token { if next_char == s.quote { s.inside_string = false } - return scan_res(.rpar, '') + return s.scan_res(.rpar, '') } // all other tokens match c { `+` { if nextc == `+` { s.pos++ - return scan_res(.inc, '') + return s.scan_res(.inc, '') } else if nextc == `=` { s.pos++ - return scan_res(.plus_assign, '') + return s.scan_res(.plus_assign, '') } - return scan_res(.plus, '') + return s.scan_res(.plus, '') } `-` { if nextc == `-` { s.pos++ - return scan_res(.dec, '') + return s.scan_res(.dec, '') } else if nextc == `=` { s.pos++ - return scan_res(.minus_assign, '') + return s.scan_res(.minus_assign, '') } - return scan_res(.minus, '') + return s.scan_res(.minus, '') } `*` { if nextc == `=` { s.pos++ - return scan_res(.mult_assign, '') + return s.scan_res(.mult_assign, '') } - return scan_res(.mul, '') + return s.scan_res(.mul, '') } `^` { if nextc == `=` { s.pos++ - return scan_res(.xor_assign, '') + return s.scan_res(.xor_assign, '') } - return scan_res(.xor, '') + return s.scan_res(.xor, '') } `%` { if nextc == `=` { s.pos++ - return scan_res(.mod_assign, '') + return s.scan_res(.mod_assign, '') } - return scan_res(.mod, '') + return s.scan_res(.mod, '') } `?` { - return scan_res(.question, '') + return s.scan_res(.question, '') } single_quote, double_quote { - return scan_res(.str, s.ident_string()) + return s.scan_res(.str, s.ident_string()) } `\`` { // ` // apostrophe balance comment. do not remove - return scan_res(.chartoken, s.ident_char()) + return s.scan_res(.chartoken, s.ident_char()) } `(` { - return scan_res(.lpar, '') + return s.scan_res(.lpar, '') } `)` { - return scan_res(.rpar, '') + return s.scan_res(.rpar, '') } `[` { - return scan_res(.lsbr, '') + return s.scan_res(.lsbr, '') } `]` { - return scan_res(.rsbr, '') + return s.scan_res(.rsbr, '') } `{` { // Skip { in `${` in strings if s.inside_string { return s.scan() } - return scan_res(.lcbr, '') + return s.scan_res(.lcbr, '') } `$` { if s.inside_string { - return scan_res(.str_dollar, '') + return s.scan_res(.str_dollar, '') } else { - return scan_res(.dollar, '') + return s.scan_res(.dollar, '') } } `}` { @@ -389,38 +389,38 @@ pub fn (s mut Scanner) scan() token.Token { s.pos++ if s.text[s.pos] == s.quote { s.inside_string = false - return scan_res(.str, '') + return s.scan_res(.str, '') } - return scan_res(.str, s.ident_string()) + return s.scan_res(.str, s.ident_string()) } else { - return scan_res(.rcbr, '') + return s.scan_res(.rcbr, '') } } `&` { if nextc == `=` { s.pos++ - return scan_res(.and_assign, '') + return s.scan_res(.and_assign, '') } if nextc == `&` { s.pos++ - return scan_res(.and, '') + return s.scan_res(.and, '') } - return scan_res(.amp, '') + return s.scan_res(.amp, '') } `|` { if nextc == `|` { s.pos++ - return scan_res(.logical_or, '') + return s.scan_res(.logical_or, '') } if nextc == `=` { s.pos++ - return scan_res(.or_assign, '') + return s.scan_res(.or_assign, '') } - return scan_res(.pipe, '') + return s.scan_res(.pipe, '') } `,` { - return scan_res(.comma, '') + return s.scan_res(.comma, '') } `@` { s.pos++ @@ -434,36 +434,36 @@ pub fn (s mut Scanner) scan() token.Token { // println( 'file: ' + @FILE + ' | line: ' + @LINE + ' | fn: ' + @FN) // ... which is useful while debugging/tracing if name == 'FN' { - return scan_res(.str, s.fn_name) + return s.scan_res(.str, s.fn_name) } if name == 'FILE' { - return scan_res(.str, cescaped_path(os.realpath(s.file_path))) + return s.scan_res(.str, cescaped_path(os.realpath(s.file_path))) } if name == 'LINE' { - return scan_res(.str, (s.line_nr + 1).str()) + return s.scan_res(.str, (s.line_nr + 1).str()) } if name == 'COLUMN' { - return scan_res(.str, (s.current_column()).str()) + return s.scan_res(.str, (s.current_column()).str()) } if name == 'VHASH' { - return scan_res(.str, vhash()) + return s.scan_res(.str, vhash()) } if !token.is_key(name) { s.error('@ must be used before keywords (e.g. `@type string`)') } - return scan_res(.name, name) + return s.scan_res(.name, name) } /* case `\r`: if nextc == `\n` { s.pos++ s.last_nl_pos = s.pos - return scan_res(.nl, '') + return s.scan_res(.nl, '') } } case `\n`: s.last_nl_pos = s.pos - return scan_res(.nl, '') + return s.scan_res(.nl, '') } */ @@ -472,11 +472,11 @@ pub fn (s mut Scanner) scan() token.Token { s.pos++ if s.text[s.pos + 1] == `.` { s.pos++ - return scan_res(.ellipsis, '') + return s.scan_res(.ellipsis, '') } - return scan_res(.dotdot, '') + return s.scan_res(.dotdot, '') } - return scan_res(.dot, '') + return s.scan_res(.dot, '') } `#` { start := s.pos + 1 @@ -488,100 +488,100 @@ pub fn (s mut Scanner) scan() token.Token { return s.scan() } hash := s.text[start..s.pos] - return scan_res(.hash, hash.trim_space()) + return s.scan_res(.hash, hash.trim_space()) } `>` { if nextc == `=` { s.pos++ - return scan_res(.ge, '') + return s.scan_res(.ge, '') } else if nextc == `>` { if s.pos + 2 < s.text.len && s.text[s.pos + 2] == `=` { s.pos += 2 - return scan_res(.righ_shift_assign, '') + return s.scan_res(.righ_shift_assign, '') } s.pos++ - return scan_res(.righ_shift, '') + return s.scan_res(.righ_shift, '') } else { - return scan_res(.gt, '') + return s.scan_res(.gt, '') } } 0xE2 { // case `≠`: if nextc == 0x89 && s.text[s.pos + 2] == 0xA0 { s.pos += 2 - return scan_res(.ne, '') + return s.scan_res(.ne, '') } // ⩽ else if nextc == 0x89 && s.text[s.pos + 2] == 0xBD { s.pos += 2 - return scan_res(.le, '') + return s.scan_res(.le, '') } // ⩾ else if nextc == 0xA9 && s.text[s.pos + 2] == 0xBE { s.pos += 2 - return scan_res(.ge, '') + return s.scan_res(.ge, '') } } `<` { if nextc == `=` { s.pos++ - return scan_res(.le, '') + return s.scan_res(.le, '') } else if nextc == `<` { if s.pos + 2 < s.text.len && s.text[s.pos + 2] == `=` { s.pos += 2 - return scan_res(.left_shift_assign, '') + return s.scan_res(.left_shift_assign, '') } s.pos++ - return scan_res(.left_shift, '') + return s.scan_res(.left_shift, '') } else { - return scan_res(.lt, '') + return s.scan_res(.lt, '') } } `=` { if nextc == `=` { s.pos++ - return scan_res(.eq, '') + return s.scan_res(.eq, '') } else if nextc == `>` { s.pos++ - return scan_res(.arrow, '') + return s.scan_res(.arrow, '') } else { - return scan_res(.assign, '') + return s.scan_res(.assign, '') } } `:` { if nextc == `=` { s.pos++ - return scan_res(.decl_assign, '') + return s.scan_res(.decl_assign, '') } else { - return scan_res(.colon, '') + return s.scan_res(.colon, '') } } `;` { - return scan_res(.semicolon, '') + return s.scan_res(.semicolon, '') } `!` { if nextc == `=` { s.pos++ - return scan_res(.ne, '') + return s.scan_res(.ne, '') } else { - return scan_res(.not, '') + return s.scan_res(.not, '') } } `~` { - return scan_res(.bit_not, '') + return s.scan_res(.bit_not, '') } `/` { if nextc == `=` { s.pos++ - return scan_res(.div_assign, '') + return s.scan_res(.div_assign, '') } if nextc == `/` { start := s.pos + 1 @@ -591,7 +591,7 @@ pub fn (s mut Scanner) scan() token.Token { if s.is_fmt { s.pos-- // fix line_nr, \n was read, and the comment is marked on the next line s.line_nr-- - return scan_res(.line_comment, s.line_comment) + return s.scan_res(.line_comment, s.line_comment) } // s.fgenln('// ${s.prev_tok.str()} "$s.line_comment"') // Skip the comment (return the next token) @@ -625,12 +625,12 @@ pub fn (s mut Scanner) scan() token.Token { comment := s.text[start..end] if s.is_fmt { s.line_comment = comment - return scan_res(.mline_comment, s.line_comment) + return s.scan_res(.mline_comment, s.line_comment) } // Skip if not in fmt mode return s.scan() } - return scan_res(.div, '') + return s.scan_res(.div, '') } else {} } diff --git a/vlib/v/table/table.v b/vlib/v/table/table.v index 13bc2e1b18..ee1bc73db9 100644 --- a/vlib/v/table/table.v +++ b/vlib/v/table/table.v @@ -2,6 +2,64 @@ module table pub struct Table { pub mut: - names []string + local_vars []Var +} + +pub struct Var { +pub: + name string + is_mut bool +} + +pub fn (t &Table) find_var(name string) ?Var { + /* + for i in 0 .. p.var_idx { + if p.local_vars[i].name == name { + return p.local_vars[i] + } + } + */ + + // println(t.names) + for var in t.local_vars { + if var.name == name { + return var + } + } + return none +} + +pub fn (t mut Table) clear_vars() { + // shared a := [1, 2, 3] + // p.var_idx = 0 + if t.local_vars.len > 0 { + // if p.pref.autofree { + // p.local_vars.free() + // } + t.local_vars = [] + } +} + +fn (t mut Table) register_var(v Var) { + t.local_vars << v + /* + mut new_var := { + v | + idx:p.var_idx, + scope_level:p.cur_fn.scope_level + } + if v.line_nr == 0 { + new_var.token_idx = p.cur_tok_index() + new_var.line_nr = p.cur_tok().line_nr + } + // Expand the array + if p.var_idx >= p.local_vars.len { + p.local_vars << new_var + } + else { + p.local_vars[p.var_idx] = new_var + } + p.var_idx++ + */ } diff --git a/vlib/v/token/token.v b/vlib/v/token/token.v index df1813ecf0..7c42d8574d 100644 --- a/vlib/v/token/token.v +++ b/vlib/v/token/token.v @@ -5,9 +5,9 @@ module token pub struct Token { pub: - kind TokenKind // the token number/enum; for quick comparisons - lit string // literal representation of the token - // line_nr int // the line number in the source where the token occured + kind TokenKind // the token number/enum; for quick comparisons + lit string // literal representation of the token + line_nr int // the line number in the source where the token occured // name_idx int // name table index for O(1) lookup // pos int // the position of the token in scanner text }