local vars + Parser.errror()

pull/3253/head
Alexander Medvednikov 2019-12-29 06:50:08 +01:00
parent c81fbee4ab
commit c915c58d12
8 changed files with 173 additions and 90 deletions

View File

@ -93,8 +93,8 @@ selfcompile:
modules: module_builtin module_strings module_strconv modules: module_builtin module_strings module_strconv
module_builtin: module_builtin:
./v build module vlib/builtin > /dev/null #./v build module vlib/builtin > /dev/null
module_strings: module_strings:
./v build module vlib/strings > /dev/null #./v build module vlib/strings > /dev/null
module_strconv: module_strconv:
./v build module vlib/strconv > /dev/null #./v build module vlib/strconv > /dev/null

View File

@ -5,6 +5,7 @@ import (
v.ast v.ast
v.cgen v.cgen
v.table v.table
term
) )
const ( const (
@ -29,7 +30,7 @@ fn test_c_files() {
eprintln('${i}... OK') eprintln('${i}... OK')
} }
else { else {
eprintln('${i}... FAIL') eprintln('${i}... ' + term.red('FAIL'))
eprintln('expected:\n$ctext\ngot:\n$res') eprintln('expected:\n$ctext\ngot:\n$res')
} }
} }

View File

@ -10,4 +10,6 @@ void function2() {
string s = tos3("hi"); string s = tos3("hi");
int m = 10; int m = 10;
x += 10; x += 10;
x += 1;
m += 2;
} }

View File

@ -9,7 +9,10 @@ fn function2() {
mut x := 0 mut x := 0
f := 10.1 f := 10.1
s := 'hi' s := 'hi'
m := 10 mut m := 10
x += 10 x += 10
x += 1
m += 2
//a += 1
//c := 0 //c := 0
} }

View File

@ -9,6 +9,7 @@ import (
v.token v.token
v.table v.table
v.types v.types
term
) )
struct Parser { struct Parser {
@ -169,9 +170,18 @@ pub fn (p mut Parser) stmt() ast.Stmt {
} }
pub fn (p mut Parser) assign_stmt() ast.AssignStmt { 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) left_expr,left_type := p.expr(0)
op := p.tok.kind op := p.tok.kind
println('assignn_stmt() ' + op.str()) //println('assignn_stmt() ' + op.str())
p.next() p.next()
right_expr,right_type := p.expr(0) right_expr,right_type := p.expr(0)
return ast.AssignStmt{ 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 // Implementation of Pratt Precedence
pub fn (p mut Parser) expr(rbp int) (ast.Expr,types.Type) { pub fn (p mut Parser) expr(rbp int) (ast.Expr,types.Type) {
// println('expr at ' + p.tok.str()) // 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 { fn (p mut Parser) fn_decl() ast.FnDecl {
p.table.clear_vars()
p.check(.key_fn) p.check(.key_fn)
name := p.tok.lit name := p.tok.lit
// println('fn decl $name') // println('fn decl $name')
@ -343,10 +359,13 @@ fn (p mut Parser) var_decl() ast.VarDecl {
name := p.tok.lit name := p.tok.lit
p.read_first_token() p.read_first_token()
expr,t := p.expr(token.lowest_prec) expr,t := p.expr(token.lowest_prec)
if name in p.table.names { if _ := p.table.find_var(name) {
verror('redefinition of `$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(p.table.names)
// println('added $name') // println('added $name')
return ast.VarDecl{ return ast.VarDecl{

View File

@ -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{ return token.Token{
tok,lit} tok,lit,s.line_nr + 1}
} }
fn (s mut Scanner) ident_name() string { 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 { fn (s mut Scanner) end_of_file() token.Token {
s.pos = s.text.len s.pos = s.text.len
s.inc_line_number() s.inc_line_number()
return scan_res(.eof, '') return s.scan_res(.eof, '')
} }
pub fn (s mut Scanner) scan() token.Token { 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.inter_end {
if s.text[s.pos] == s.quote { if s.text[s.pos] == s.quote {
s.inter_end = false s.inter_end = false
return scan_res(.str, '') return s.scan_res(.str, '')
} }
s.inter_end = false s.inter_end = false
return scan_res(.str, s.ident_string()) return s.scan_res(.str, s.ident_string())
} }
s.skip_whitespace() s.skip_whitespace()
// end of file // end of file
@ -261,7 +261,7 @@ pub fn (s mut Scanner) scan() token.Token {
// Check if not .eof to prevent panic // Check if not .eof to prevent panic
next_char := if s.pos + 1 < s.text.len { s.text[s.pos + 1] } else { `\0` } next_char := if s.pos + 1 < s.text.len { s.text[s.pos + 1] } else { `\0` }
if token.is_key(name) { 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 // 'asdf $b' => "b" is the last name in the string, dont start parsing string
// at the next ', skip it // 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 // Otherwise the scanner would be stuck at s.pos = 0
s.pos++ s.pos++
} }
return scan_res(.name, name) return s.scan_res(.name, name)
} }
// `123`, `.123` // `123`, `.123`
else if c.is_digit() || (c == `.` && nextc.is_digit()) { else if c.is_digit() || (c == `.` && nextc.is_digit()) {
num := s.ident_number() num := s.ident_number()
return scan_res(.number, num) return s.scan_res(.number, num)
} }
// Handle `'$fn()'` // Handle `'$fn()'`
if c == `)` && s.inter_start { if c == `)` && s.inter_start {
@ -298,88 +298,88 @@ pub fn (s mut Scanner) scan() token.Token {
if next_char == s.quote { if next_char == s.quote {
s.inside_string = false s.inside_string = false
} }
return scan_res(.rpar, '') return s.scan_res(.rpar, '')
} }
// all other tokens // all other tokens
match c { match c {
`+` { `+` {
if nextc == `+` { if nextc == `+` {
s.pos++ s.pos++
return scan_res(.inc, '') return s.scan_res(.inc, '')
} }
else if nextc == `=` { else if nextc == `=` {
s.pos++ s.pos++
return scan_res(.plus_assign, '') return s.scan_res(.plus_assign, '')
} }
return scan_res(.plus, '') return s.scan_res(.plus, '')
} }
`-` { `-` {
if nextc == `-` { if nextc == `-` {
s.pos++ s.pos++
return scan_res(.dec, '') return s.scan_res(.dec, '')
} }
else if nextc == `=` { else if nextc == `=` {
s.pos++ s.pos++
return scan_res(.minus_assign, '') return s.scan_res(.minus_assign, '')
} }
return scan_res(.minus, '') return s.scan_res(.minus, '')
} }
`*` { `*` {
if nextc == `=` { if nextc == `=` {
s.pos++ s.pos++
return scan_res(.mult_assign, '') return s.scan_res(.mult_assign, '')
} }
return scan_res(.mul, '') return s.scan_res(.mul, '')
} }
`^` { `^` {
if nextc == `=` { if nextc == `=` {
s.pos++ s.pos++
return scan_res(.xor_assign, '') return s.scan_res(.xor_assign, '')
} }
return scan_res(.xor, '') return s.scan_res(.xor, '')
} }
`%` { `%` {
if nextc == `=` { if nextc == `=` {
s.pos++ 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 { 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 // ` // 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 // Skip { in `${` in strings
if s.inside_string { if s.inside_string {
return s.scan() return s.scan()
} }
return scan_res(.lcbr, '') return s.scan_res(.lcbr, '')
} }
`$` { `$` {
if s.inside_string { if s.inside_string {
return scan_res(.str_dollar, '') return s.scan_res(.str_dollar, '')
} }
else { else {
return scan_res(.dollar, '') return s.scan_res(.dollar, '')
} }
} }
`}` { `}` {
@ -389,38 +389,38 @@ pub fn (s mut Scanner) scan() token.Token {
s.pos++ s.pos++
if s.text[s.pos] == s.quote { if s.text[s.pos] == s.quote {
s.inside_string = false 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 { else {
return scan_res(.rcbr, '') return s.scan_res(.rcbr, '')
} }
} }
`&` { `&` {
if nextc == `=` { if nextc == `=` {
s.pos++ s.pos++
return scan_res(.and_assign, '') return s.scan_res(.and_assign, '')
} }
if nextc == `&` { if nextc == `&` {
s.pos++ s.pos++
return scan_res(.and, '') return s.scan_res(.and, '')
} }
return scan_res(.amp, '') return s.scan_res(.amp, '')
} }
`|` { `|` {
if nextc == `|` { if nextc == `|` {
s.pos++ s.pos++
return scan_res(.logical_or, '') return s.scan_res(.logical_or, '')
} }
if nextc == `=` { if nextc == `=` {
s.pos++ 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++ s.pos++
@ -434,36 +434,36 @@ pub fn (s mut Scanner) scan() token.Token {
// println( 'file: ' + @FILE + ' | line: ' + @LINE + ' | fn: ' + @FN) // println( 'file: ' + @FILE + ' | line: ' + @LINE + ' | fn: ' + @FN)
// ... which is useful while debugging/tracing // ... which is useful while debugging/tracing
if name == 'FN' { if name == 'FN' {
return scan_res(.str, s.fn_name) return s.scan_res(.str, s.fn_name)
} }
if name == 'FILE' { 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' { 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' { if name == 'COLUMN' {
return scan_res(.str, (s.current_column()).str()) return s.scan_res(.str, (s.current_column()).str())
} }
if name == 'VHASH' { if name == 'VHASH' {
return scan_res(.str, vhash()) return s.scan_res(.str, vhash())
} }
if !token.is_key(name) { if !token.is_key(name) {
s.error('@ must be used before keywords (e.g. `@type string`)') s.error('@ must be used before keywords (e.g. `@type string`)')
} }
return scan_res(.name, name) return s.scan_res(.name, name)
} }
/* /*
case `\r`: case `\r`:
if nextc == `\n` { if nextc == `\n` {
s.pos++ s.pos++
s.last_nl_pos = s.pos s.last_nl_pos = s.pos
return scan_res(.nl, '') return s.scan_res(.nl, '')
} }
} }
case `\n`: case `\n`:
s.last_nl_pos = s.pos 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++ s.pos++
if s.text[s.pos + 1] == `.` { if s.text[s.pos + 1] == `.` {
s.pos++ 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 start := s.pos + 1
@ -488,100 +488,100 @@ pub fn (s mut Scanner) scan() token.Token {
return s.scan() return s.scan()
} }
hash := s.text[start..s.pos] hash := s.text[start..s.pos]
return scan_res(.hash, hash.trim_space()) return s.scan_res(.hash, hash.trim_space())
} }
`>` { `>` {
if nextc == `=` { if nextc == `=` {
s.pos++ s.pos++
return scan_res(.ge, '') return s.scan_res(.ge, '')
} }
else if nextc == `>` { else if nextc == `>` {
if s.pos + 2 < s.text.len && s.text[s.pos + 2] == `=` { if s.pos + 2 < s.text.len && s.text[s.pos + 2] == `=` {
s.pos += 2 s.pos += 2
return scan_res(.righ_shift_assign, '') return s.scan_res(.righ_shift_assign, '')
} }
s.pos++ s.pos++
return scan_res(.righ_shift, '') return s.scan_res(.righ_shift, '')
} }
else { else {
return scan_res(.gt, '') return s.scan_res(.gt, '')
} }
} }
0xE2 { 0xE2 {
// case `≠`: // case `≠`:
if nextc == 0x89 && s.text[s.pos + 2] == 0xA0 { if nextc == 0x89 && s.text[s.pos + 2] == 0xA0 {
s.pos += 2 s.pos += 2
return scan_res(.ne, '') return s.scan_res(.ne, '')
} }
// ⩽ // ⩽
else if nextc == 0x89 && s.text[s.pos + 2] == 0xBD { else if nextc == 0x89 && s.text[s.pos + 2] == 0xBD {
s.pos += 2 s.pos += 2
return scan_res(.le, '') return s.scan_res(.le, '')
} }
// ⩾ // ⩾
else if nextc == 0xA9 && s.text[s.pos + 2] == 0xBE { else if nextc == 0xA9 && s.text[s.pos + 2] == 0xBE {
s.pos += 2 s.pos += 2
return scan_res(.ge, '') return s.scan_res(.ge, '')
} }
} }
`<` { `<` {
if nextc == `=` { if nextc == `=` {
s.pos++ s.pos++
return scan_res(.le, '') return s.scan_res(.le, '')
} }
else if nextc == `<` { else if nextc == `<` {
if s.pos + 2 < s.text.len && s.text[s.pos + 2] == `=` { if s.pos + 2 < s.text.len && s.text[s.pos + 2] == `=` {
s.pos += 2 s.pos += 2
return scan_res(.left_shift_assign, '') return s.scan_res(.left_shift_assign, '')
} }
s.pos++ s.pos++
return scan_res(.left_shift, '') return s.scan_res(.left_shift, '')
} }
else { else {
return scan_res(.lt, '') return s.scan_res(.lt, '')
} }
} }
`=` { `=` {
if nextc == `=` { if nextc == `=` {
s.pos++ s.pos++
return scan_res(.eq, '') return s.scan_res(.eq, '')
} }
else if nextc == `>` { else if nextc == `>` {
s.pos++ s.pos++
return scan_res(.arrow, '') return s.scan_res(.arrow, '')
} }
else { else {
return scan_res(.assign, '') return s.scan_res(.assign, '')
} }
} }
`:` { `:` {
if nextc == `=` { if nextc == `=` {
s.pos++ s.pos++
return scan_res(.decl_assign, '') return s.scan_res(.decl_assign, '')
} }
else { else {
return scan_res(.colon, '') return s.scan_res(.colon, '')
} }
} }
`;` { `;` {
return scan_res(.semicolon, '') return s.scan_res(.semicolon, '')
} }
`!` { `!` {
if nextc == `=` { if nextc == `=` {
s.pos++ s.pos++
return scan_res(.ne, '') return s.scan_res(.ne, '')
} }
else { else {
return scan_res(.not, '') return s.scan_res(.not, '')
} }
} }
`~` { `~` {
return scan_res(.bit_not, '') return s.scan_res(.bit_not, '')
} }
`/` { `/` {
if nextc == `=` { if nextc == `=` {
s.pos++ s.pos++
return scan_res(.div_assign, '') return s.scan_res(.div_assign, '')
} }
if nextc == `/` { if nextc == `/` {
start := s.pos + 1 start := s.pos + 1
@ -591,7 +591,7 @@ pub fn (s mut Scanner) scan() token.Token {
if s.is_fmt { if s.is_fmt {
s.pos-- // fix line_nr, \n was read, and the comment is marked on the next line s.pos-- // fix line_nr, \n was read, and the comment is marked on the next line
s.line_nr-- 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"') // s.fgenln('// ${s.prev_tok.str()} "$s.line_comment"')
// Skip the comment (return the next token) // Skip the comment (return the next token)
@ -625,12 +625,12 @@ pub fn (s mut Scanner) scan() token.Token {
comment := s.text[start..end] comment := s.text[start..end]
if s.is_fmt { if s.is_fmt {
s.line_comment = comment 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 // Skip if not in fmt mode
return s.scan() return s.scan()
} }
return scan_res(.div, '') return s.scan_res(.div, '')
} }
else {} else {}
} }

View File

@ -2,6 +2,64 @@ module table
pub struct Table { pub struct Table {
pub mut: 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++
*/
} }

View File

@ -5,9 +5,9 @@ module token
pub struct Token { pub struct Token {
pub: pub:
kind TokenKind // the token number/enum; for quick comparisons kind TokenKind // the token number/enum; for quick comparisons
lit string // literal representation of the token lit string // literal representation of the token
// line_nr int // the line number in the source where the token occured line_nr int // the line number in the source where the token occured
// name_idx int // name table index for O(1) lookup // name_idx int // name table index for O(1) lookup
// pos int // the position of the token in scanner text // pos int // the position of the token in scanner text
} }