go back to `mut`. decisions, decisions...

pull/4534/head^2
Alexander Medvednikov 2020-04-21 05:11:50 +02:00
parent 1bf094fbca
commit ee2e83fef0
7 changed files with 284 additions and 284 deletions

View File

@ -126,16 +126,16 @@ Unlike most other languages, V only allows defining variables in functions.
Global (module level) variables are not allowed. There's no global state in V. Global (module level) variables are not allowed. There's no global state in V.
```v ```v
var age := 20 mut age := 20
println(age) println(age)
age = 21 age = 21
println(age) println(age)
``` ```
To change the value of the variable use `=`. In V, variables are To change the value of the variable use `=`. In V, variables are
immutable by default. To be able to change the value of the variable, you have to declare it with `var`. immutable by default. To be able to change the value of the variable, you have to declare it with `mut`.
Try compiling the program above after removing `var` from the first line. Try compiling the program above after removing `mut` from the first line.
Please note the difference between `:=` and `=` Please note the difference between `:=` and `=`
`:=` is used for declaring and initializing, `=` is used for assigning. `:=` is used for declaring and initializing, `=` is used for assigning.
@ -200,7 +200,7 @@ bobby := name + 'by' // + is used to concatenate strings
println(bobby) // "Bobby" println(bobby) // "Bobby"
println(bobby[1..3]) // "ob" println(bobby[1..3]) // "ob"
var s := 'hello ' mut s := 'hello '
s += 'world' // `+=` is used to append to a string s += 'world' // `+=` is used to append to a string
println(s) // "hello world" println(s) // "hello world"
``` ```
@ -264,7 +264,7 @@ Modules can be imported using keyword `import`. When using types, functions, and
## Arrays ## Arrays
```v ```v
var nums := [1, 2, 3] mut nums := [1, 2, 3]
println(nums) // "[1, 2, 3]" println(nums) // "[1, 2, 3]"
println(nums[1]) // "2" println(nums[1]) // "2"
@ -274,7 +274,7 @@ println(nums) // "[1, 2, 3, 4]"
nums << [5, 6, 7] nums << [5, 6, 7]
println(nums) // "[1, 2, 3, 4, 5, 6, 7]" println(nums) // "[1, 2, 3, 4, 5, 6, 7]"
var names := ['John'] mut names := ['John']
names << 'Peter' names << 'Peter'
names << 'Sam' names << 'Sam'
// names << 10 <-- This will not compile. `names` is an array of strings. // names << 10 <-- This will not compile. `names` is an array of strings.
@ -322,7 +322,7 @@ println(upper) // ['HELLO', 'WORLD']
## Maps ## Maps
```v ```v
var m := map[string]int // Only maps with string keys are allowed for now mut m := map[string]int // Only maps with string keys are allowed for now
m['one'] = 1 m['one'] = 1
m['two'] = 2 m['two'] = 2
println(m['one']) // "1" println(m['one']) // "1"
@ -414,7 +414,7 @@ If an index is required, an alternative form `for index, value in` can be used.
Note, that the value is read-only. If you need to modify the array while looping, you have to use indexing: Note, that the value is read-only. If you need to modify the array while looping, you have to use indexing:
```v ```v
var numbers := [1, 2, 3, 4, 5] mut numbers := [1, 2, 3, 4, 5]
for i, num in numbers { for i, num in numbers {
println(num) println(num)
numbers[i] = 0 numbers[i] = 0
@ -422,8 +422,8 @@ for i, num in numbers {
``` ```
```v ```v
var sum := 0 mut sum := 0
var i := 0 mut i := 0
for i <= 100 { for i <= 100 {
sum += i sum += i
i++ i++
@ -438,7 +438,7 @@ The loop will stop iterating once the boolean condition evaluates to false.
Again, there are no parentheses surrounding the condition, and the braces are always required. Again, there are no parentheses surrounding the condition, and the braces are always required.
```v ```v
var num := 0 mut num := 0
for { for {
num++ num++
if num >= 10 { if num >= 10 {
@ -464,7 +464,7 @@ Finally, there's the traditional C style `for` loop. It's safer than the `while`
because with the latter it's easy to forget to update the counter and get because with the latter it's easy to forget to update the counter and get
stuck in an infinite loop. stuck in an infinite loop.
Here `i` doesn't need to be declared with `var` since it's always going to be mutable by definition. Here `i` doesn't need to be declared with `mut` since it's always going to be mutable by definition.
## Match ## Match
@ -557,7 +557,7 @@ button.widget.set_pos(x,y)
Struct fields are private and immutable by default (making structs immutable as well). Struct fields are private and immutable by default (making structs immutable as well).
Their access modifiers can be changed with Their access modifiers can be changed with
`pub` and `var`. In total, there are 5 possible options: `pub` and `mut`. In total, there are 5 possible options:
```v ```v
struct Foo { struct Foo {
@ -633,7 +633,7 @@ This is achieved by lack of global variables and all function arguments being im
even when references are passed. even when references are passed.
V is not a pure functional language however. V is not a pure functional language however.
It is possible to modify function arguments by using the same keyword `var`: It is possible to modify function arguments by using the same keyword `mut`:
```v ```v
struct User { struct User {
@ -641,11 +641,11 @@ var:
is_registered bool is_registered bool
} }
fn (var u User) register() { fn (mut u User) register() {
u.is_registered = true u.is_registered = true
} }
var user := User{} mut user := User{}
println(user.is_registered) // "false" println(user.is_registered) // "false"
user.register() user.register()
println(user.is_registered) // "true" println(user.is_registered) // "true"
@ -655,18 +655,18 @@ In this example, the receiver (which is simply the first argument) is marked as
so `register()` can change the user object. The same works with non-receiver arguments: so `register()` can change the user object. The same works with non-receiver arguments:
```v ```v
fn multiply_by_2(var arr []int) { fn multiply_by_2(mut arr []int) {
for i in 0..arr.len { for i in 0..arr.len {
arr[i] *= 2 arr[i] *= 2
} }
} }
var nums := [1, 2, 3] mut nums := [1, 2, 3]
multiply_by_2(var nums) multiply_by_2(mut nums)
println(nums) // "[2, 4, 6]" println(nums) // "[2, 4, 6]"
``` ```
Note, that you have to add `var` before `nums` when calling this function. This makes Note, that you have to add `mut` before `nums` when calling this function. This makes
it clear that the function being called will modify the value. it clear that the function being called will modify the value.
It is preferable to return values instead of modifying arguments. It is preferable to return values instead of modifying arguments.
@ -677,7 +677,7 @@ For this reason V doesn't allow to modify primitive args like integers, only
complex types like arrays and maps. complex types like arrays and maps.
Use `user.register()` or `user = register(user)` Use `user.register()` or `user = register(user)`
instead of `register(var user)`. instead of `register(mut user)`.
V makes it easy to return a modified version of an object: V makes it easy to return a modified version of an object:
@ -734,7 +734,7 @@ fn (foo &Foo) bar() {
``` ```
`foo` is still immutable and can't be changed. For that, `foo` is still immutable and can't be changed. For that,
`(var foo Foo)` has to be used. `(mut foo Foo)` has to be used.
In general, V references are similar to Go pointers and C++ references. In general, V references are similar to Go pointers and C++ references.
For example, a tree structure definition would look like this: For example, a tree structure definition would look like this:
@ -917,7 +917,7 @@ enum Color {
red green blue red green blue
} }
var color := Color.red mut color := Color.red
// V knows that `color` is a `Color`. No need to use `color = Color.green` here. // V knows that `color` is a `Color`. No need to use `color = Color.green` here.
color = .green color = .green
println(color) // "1" TODO: print "green"? println(color) // "1" TODO: print "green"?
@ -1385,7 +1385,7 @@ serializers for anything:
```v ```v
// TODO: not implemented yet // TODO: not implemented yet
fn decode<T>(data string) T { fn decode<T>(data string) T {
var result := T{} mut result := T{}
for field in T.fields { for field in T.fields {
if field.typ == 'string' { if field.typ == 'string' {
result.$field = get_string(data, field.name) result.$field = get_string(data, field.name)
@ -1398,7 +1398,7 @@ fn decode<T>(data string) T {
// generates to: // generates to:
fn decode_User(data string) User { fn decode_User(data string) User {
var result := User{} mut result := User{}
result.name = get_string(data, 'name') result.name = get_string(data, 'name')
result.age = get_int(data, 'age') result.age = get_int(data, 'age')
return result return result
@ -1492,7 +1492,7 @@ Run `v translate test.cpp` and V will generate `test.v`:
```v ```v
fn main { fn main {
var s := [] mut s := []
s << 'V is ' s << 'V is '
s << 'awesome' s << 'awesome'
println(s.len) println(s.len)

View File

@ -8,16 +8,16 @@ import v.table
import strings import strings
pub fn (node &FnDecl) str(t &table.Table) string { pub fn (node &FnDecl) str(t &table.Table) string {
var f := strings.new_builder(30) mut f := strings.new_builder(30)
if node.is_pub { if node.is_pub {
f.write('pub ') f.write('pub ')
} }
var receiver := '' mut receiver := ''
if node.is_method { if node.is_method {
var styp := t.type_to_str(node.receiver.typ) mut styp := t.type_to_str(node.receiver.typ)
var m := if node.rec_mut { 'var ' } else { '' } mut m := if node.rec_mut { 'mut ' } else { '' }
if node.rec_mut { if node.rec_mut {
styp = styp[1..] // remove & styp = styp[1..] // remove &
} }
receiver = '($m$node.receiver.name $styp) ' receiver = '($m$node.receiver.name $styp) '
/* /*
@ -30,7 +30,7 @@ pub fn (node &FnDecl) str(t &table.Table) string {
receiver = '($node.receiver.name $m$name) ' receiver = '($node.receiver.name $m$name) '
*/ */
} }
var name := node.name.after('.') mut name := node.name.after('.')
if node.is_c { if node.is_c {
name = 'C.$name' name = 'C.$name'
} }
@ -47,7 +47,7 @@ pub fn (node &FnDecl) str(t &table.Table) string {
should_add_type := is_last_arg || node.args[i + 1].typ != arg.typ || (node.is_variadic && should_add_type := is_last_arg || node.args[i + 1].typ != arg.typ || (node.is_variadic &&
i == node.args.len - 2) i == node.args.len - 2)
f.write(arg.name) f.write(arg.name)
var s := t.type_to_str(arg.typ) mut s := t.type_to_str(arg.typ)
if arg.is_mut { if arg.is_mut {
f.write(' mut') f.write(' mut')
if s.starts_with('&') { if s.starts_with('&') {
@ -161,7 +161,7 @@ pub fn (a CallArg) str() string {
} }
pub fn args2str(args []CallArg) string { pub fn args2str(args []CallArg) string {
var res := []string mut res := []string
for a in args { for a in args {
res << a.str() res << a.str()
} }
@ -171,7 +171,7 @@ pub fn args2str(args []CallArg) string {
pub fn (node Stmt) str() string { pub fn (node Stmt) str() string {
match node { match node {
AssignStmt { AssignStmt {
var out := '' mut out := ''
for i, ident in it.left { for i, ident in it.left {
var_info := ident.var_info() var_info := ident.var_info()
if var_info.is_mut { if var_info.is_mut {

View File

@ -31,7 +31,7 @@ mut:
} }
pub fn fmt(file ast.File, table &table.Table) string { pub fn fmt(file ast.File, table &table.Table) string {
var f := Fmt{ mut f := Fmt{
out: strings.new_builder(1000) out: strings.new_builder(1000)
out_imports: strings.new_builder(200) out_imports: strings.new_builder(200)
table: table table: table
@ -67,7 +67,7 @@ fn (f mut Fmt) find_comment(line_nr int) {
} }
} }
*/ */
pub fn (var f Fmt) write(s string) { pub fn (mut f Fmt) write(s string) {
if f.indent > 0 && f.empty_line { if f.indent > 0 && f.empty_line {
f.out.write(tabs[f.indent]) f.out.write(tabs[f.indent])
f.line_len += f.indent * 4 f.line_len += f.indent * 4
@ -77,7 +77,7 @@ pub fn (var f Fmt) write(s string) {
f.empty_line = false f.empty_line = false
} }
pub fn (var f Fmt) writeln(s string) { pub fn (mut f Fmt) writeln(s string) {
if f.indent > 0 && f.empty_line { if f.indent > 0 && f.empty_line {
// println(f.indent.str() + s) // println(f.indent.str() + s)
f.out.write(tabs[f.indent]) f.out.write(tabs[f.indent])
@ -87,7 +87,7 @@ pub fn (var f Fmt) writeln(s string) {
f.line_len = 0 f.line_len = 0
} }
fn (var f Fmt) mod(mod ast.Module) { fn (mut f Fmt) mod(mod ast.Module) {
f.cur_mod = mod.name f.cur_mod = mod.name
if mod.is_skipped { if mod.is_skipped {
return return
@ -95,7 +95,7 @@ fn (var f Fmt) mod(mod ast.Module) {
f.writeln('module $mod.name\n') f.writeln('module $mod.name\n')
} }
fn (var f Fmt) imports(imports []ast.Import) { fn (mut f Fmt) imports(imports []ast.Import) {
if f.did_imports || imports.len == 0 { if f.did_imports || imports.len == 0 {
return return
} }
@ -129,7 +129,7 @@ fn (f Fmt) imp_stmt_str(imp ast.Import) string {
return '${imp.mod}${imp_alias_suffix}' return '${imp.mod}${imp_alias_suffix}'
} }
fn (var f Fmt) stmts(stmts []ast.Stmt) { fn (mut f Fmt) stmts(stmts []ast.Stmt) {
f.indent++ f.indent++
for stmt in stmts { for stmt in stmts {
f.stmt(stmt) f.stmt(stmt)
@ -137,13 +137,13 @@ fn (var f Fmt) stmts(stmts []ast.Stmt) {
f.indent-- f.indent--
} }
fn (var f Fmt) stmt(node ast.Stmt) { fn (mut f Fmt) stmt(node ast.Stmt) {
match node { match node {
ast.AssignStmt { ast.AssignStmt {
for i, ident in it.left { for i, ident in it.left {
var_info := ident.var_info() var_info := ident.var_info()
if var_info.is_mut { if var_info.is_mut {
f.write('var ') f.write('mut ')
} }
f.expr(ident) f.expr(ident)
if i < it.left.len - 1 { if i < it.left.len - 1 {
@ -201,7 +201,7 @@ fn (var f Fmt) stmt(node ast.Stmt) {
f.write('pub ') f.write('pub ')
} }
f.writeln('const (') f.writeln('const (')
var max := 0 mut max := 0
for field in it.fields { for field in it.fields {
if field.name.len > max { if field.name.len > max {
max = field.name.len max = field.name.len
@ -375,7 +375,7 @@ fn (var f Fmt) stmt(node ast.Stmt) {
} }
} }
fn (var f Fmt) type_decl(node ast.TypeDecl) { fn (mut f Fmt) type_decl(node ast.TypeDecl) {
match node { match node {
ast.AliasTypeDecl { ast.AliasTypeDecl {
if it.is_pub { if it.is_pub {
@ -389,7 +389,7 @@ fn (var f Fmt) type_decl(node ast.TypeDecl) {
f.write('pub ') f.write('pub ')
} }
f.write('type $it.name = ') f.write('type $it.name = ')
var sum_type_names := []string mut sum_type_names := []string
for t in it.sub_types { for t in it.sub_types {
sum_type_names << f.type_to_str(t) sum_type_names << f.type_to_str(t)
} }
@ -402,13 +402,13 @@ fn (var f Fmt) type_decl(node ast.TypeDecl) {
f.writeln('\n') f.writeln('\n')
} }
fn (var f Fmt) struct_decl(node ast.StructDecl) { fn (mut f Fmt) struct_decl(node ast.StructDecl) {
if node.is_pub { if node.is_pub {
f.write('pub ') f.write('pub ')
} }
name := node.name.after('.') name := node.name.after('.')
f.writeln('struct $name {') f.writeln('struct $name {')
var max := 0 mut max := 0
for field in node.fields { for field in node.fields {
if field.name.len > max { if field.name.len > max {
max = field.name.len max = field.name.len
@ -449,7 +449,7 @@ fn (var f Fmt) struct_decl(node ast.StructDecl) {
} }
fn (f &Fmt) type_to_str(t table.Type) string { fn (f &Fmt) type_to_str(t table.Type) string {
var res := f.table.type_to_str(t) mut res := f.table.type_to_str(t)
// type_ptr => &type // type_ptr => &type
if res.ends_with('_ptr') { if res.ends_with('_ptr') {
res = res[0..res.len - 4] res = res[0..res.len - 4]
@ -459,7 +459,7 @@ fn (f &Fmt) type_to_str(t table.Type) string {
return res.replace(f.cur_mod + '.', '') return res.replace(f.cur_mod + '.', '')
} }
fn (var f Fmt) expr(node ast.Expr) { fn (mut f Fmt) expr(node ast.Expr) {
match node { match node {
ast.ArrayInit { ast.ArrayInit {
if it.exprs.len == 0 && it.typ != 0 && it.typ != table.void_type { if it.exprs.len == 0 && it.typ != 0 && it.typ != table.void_type {
@ -469,8 +469,8 @@ fn (var f Fmt) expr(node ast.Expr) {
// `[1,2,3]` // `[1,2,3]`
// type_sym := f.table.get_type_symbol(it.typ) // type_sym := f.table.get_type_symbol(it.typ)
f.write('[') f.write('[')
var inc_indent := false mut inc_indent := false
var line_nr := node.position().line_nr // to have the same newlines between array elements mut line_nr := node.position().line_nr // to have the same newlines between array elements
for i, expr in it.exprs { for i, expr in it.exprs {
pos := expr.position() pos := expr.position()
if i == 0 && line_nr < pos.line_nr { if i == 0 && line_nr < pos.line_nr {
@ -663,7 +663,7 @@ fn (var f Fmt) expr(node ast.Expr) {
ast.StructInit { ast.StructInit {
type_sym := f.table.get_type_symbol(it.typ) type_sym := f.table.get_type_symbol(it.typ)
// f.write('<old name: $type_sym.name>') // f.write('<old name: $type_sym.name>')
var name := short_module(type_sym.name).replace(f.cur_mod + '.', '') // TODO f.type_to_str? mut name := short_module(type_sym.name).replace(f.cur_mod + '.', '') // TODO f.type_to_str?
if name == 'void' { if name == 'void' {
name = '' name = ''
} }
@ -709,7 +709,7 @@ fn (var f Fmt) expr(node ast.Expr) {
} }
} }
fn (var f Fmt) wrap_long_line() { fn (mut f Fmt) wrap_long_line() {
if f.line_len > max_len { if f.line_len > max_len {
if f.out.buf[f.out.buf.len - 1] == ` ` { if f.out.buf[f.out.buf.len - 1] == ` ` {
f.out.go_back(1) f.out.go_back(1)
@ -719,7 +719,7 @@ fn (var f Fmt) wrap_long_line() {
} }
} }
fn (var f Fmt) call_args(args []ast.CallArg) { fn (mut f Fmt) call_args(args []ast.CallArg) {
for i, arg in args { for i, arg in args {
if arg.is_mut { if arg.is_mut {
f.write('mut ') f.write('mut ')
@ -734,7 +734,7 @@ fn (var f Fmt) call_args(args []ast.CallArg) {
} }
} }
fn (var f Fmt) or_expr(or_block ast.OrExpr) { fn (mut f Fmt) or_expr(or_block ast.OrExpr) {
if or_block.stmts.len > 0 { if or_block.stmts.len > 0 {
f.writeln(' or {') f.writeln(' or {')
f.stmts(or_block.stmts) f.stmts(or_block.stmts)
@ -742,10 +742,10 @@ fn (var f Fmt) or_expr(or_block ast.OrExpr) {
} }
} }
fn (var f Fmt) comment(node ast.Comment) { fn (mut f Fmt) comment(node ast.Comment) {
if !node.text.contains('\n') { if !node.text.contains('\n') {
is_separate_line := node.text.starts_with('|') is_separate_line := node.text.starts_with('|')
var s := if is_separate_line { node.text[1..] } else { node.text } mut s := if is_separate_line { node.text[1..] } else { node.text }
if s == '' { if s == '' {
s = '//' s = '//'
} else { } else {
@ -779,7 +779,7 @@ fn short_module(name string) string {
return vals[vals.len - 2] + '.' + vals[vals.len - 1] return vals[vals.len - 2] + '.' + vals[vals.len - 1]
} }
fn (var f Fmt) if_expr(it ast.IfExpr) { fn (mut f Fmt) if_expr(it ast.IfExpr) {
single_line := it.branches.len == 2 && it.has_else && it.branches[0].stmts.len == 1 && single_line := it.branches.len == 2 && it.has_else && it.branches[0].stmts.len == 1 &&
it.branches[1].stmts.len == 1 && (it.is_expr || f.is_assign) it.branches[1].stmts.len == 1 && (it.is_expr || f.is_assign)
f.single_line_if = single_line f.single_line_if = single_line
@ -812,7 +812,7 @@ fn (var f Fmt) if_expr(it ast.IfExpr) {
f.single_line_if = false f.single_line_if = false
} }
fn (var f Fmt) call_expr(node ast.CallExpr) { fn (mut f Fmt) call_expr(node ast.CallExpr) {
if node.is_method { if node.is_method {
match node.left { match node.left {
ast.Ident { ast.Ident {
@ -849,15 +849,15 @@ fn (var f Fmt) call_expr(node ast.CallExpr) {
} }
} }
fn (var f Fmt) match_expr(it ast.MatchExpr) { fn (mut f Fmt) match_expr(it ast.MatchExpr) {
f.write('match ') f.write('match ')
if it.is_mut { if it.is_mut {
f.write('var ') f.write('mut ')
} }
f.expr(it.cond) f.expr(it.cond)
f.writeln(' {') f.writeln(' {')
f.indent++ f.indent++
var single_line := true mut single_line := true
for i, branch in it.branches { for i, branch in it.branches {
if branch.stmts.len > 1 { if branch.stmts.len > 1 {
single_line = false single_line = false
@ -913,8 +913,8 @@ fn (var f Fmt) match_expr(it ast.MatchExpr) {
f.write('}') f.write('}')
} }
fn (var f Fmt) remove_new_line() { fn (mut f Fmt) remove_new_line() {
var i := 0 mut i := 0
for i = f.out.len - 1; i >= 0; i-- { for i = f.out.len - 1; i >= 0; i-- {
if !f.out.buf[i].is_space() { // != `\n` { if !f.out.buf[i].is_space() { // != `\n` {
break break
@ -925,13 +925,13 @@ fn (var f Fmt) remove_new_line() {
// f.writeln('sdf') // f.writeln('sdf')
} }
fn (var f Fmt) mark_types_module_as_used(typ table.Type) { fn (mut f Fmt) mark_types_module_as_used(typ table.Type) {
sym := f.table.get_type_symbol(typ) sym := f.table.get_type_symbol(typ)
f.mark_module_as_used(sym.name) f.mark_module_as_used(sym.name)
} }
// `name` is a function (`foo.bar()`) or type (`foo.Bar{}`) // `name` is a function (`foo.bar()`) or type (`foo.Bar{}`)
fn (var f Fmt) mark_module_as_used(name string) { fn (mut f Fmt) mark_module_as_used(name string) {
if !name.contains('.') { if !name.contains('.') {
return return
} }

View File

@ -96,7 +96,7 @@ pub fn cgen(files []ast.File, table &table.Table, pref &pref.Preferences) string
} else { } else {
} }
// println('start cgen2') // println('start cgen2')
var g := Gen{ mut g := Gen{
out: strings.new_builder(1000) out: strings.new_builder(1000)
cheaders: strings.new_builder(8192) cheaders: strings.new_builder(8192)
includes: strings.new_builder(100) includes: strings.new_builder(100)
@ -114,7 +114,7 @@ pub fn cgen(files []ast.File, table &table.Table, pref &pref.Preferences) string
} }
g.init() g.init()
// //
var autofree_used := false mut autofree_used := false
for file in files { for file in files {
g.file = file g.file = file
// println('\ncgen "$g.file.path" nr_stmts=$file.stmts.len') // println('\ncgen "$g.file.path" nr_stmts=$file.stmts.len')
@ -154,12 +154,12 @@ pub fn cgen(files []ast.File, table &table.Table, pref &pref.Preferences) string
} }
pub fn (g Gen) hashes() string { pub fn (g Gen) hashes() string {
var res := c_commit_hash_default.replace('@@@', util.vhash()) mut res := c_commit_hash_default.replace('@@@', util.vhash())
res += c_current_commit_hash_default.replace('@@@', util.githash(g.pref.building_v)) res += c_current_commit_hash_default.replace('@@@', util.githash(g.pref.building_v))
return res return res
} }
pub fn (var g Gen) init() { pub fn (mut g Gen) init() {
g.cheaders.writeln('// Generated by the V compiler') g.cheaders.writeln('// Generated by the V compiler')
g.cheaders.writeln('#include <inttypes.h>') // int64_t etc g.cheaders.writeln('#include <inttypes.h>') // int64_t etc
g.cheaders.writeln(c_builtin_types) g.cheaders.writeln(c_builtin_types)
@ -184,7 +184,7 @@ pub fn (var g Gen) init() {
} }
} }
pub fn (var g Gen) finish() { pub fn (mut g Gen) finish() {
if g.pref.build_mode != .build_module { if g.pref.build_mode != .build_module {
g.stringliterals.writeln('}') g.stringliterals.writeln('}')
} }
@ -192,7 +192,7 @@ pub fn (var g Gen) finish() {
g.stringliterals.writeln('') g.stringliterals.writeln('')
} }
pub fn (var g Gen) write_typeof_functions() { pub fn (mut g Gen) write_typeof_functions() {
g.writeln('') g.writeln('')
g.writeln('// >> typeof() support for sum types') g.writeln('// >> typeof() support for sum types')
for typ in g.table.types { for typ in g.table.types {
@ -216,10 +216,10 @@ pub fn (var g Gen) write_typeof_functions() {
} }
// V type to C type // V type to C type
pub fn (var g Gen) typ(t table.Type) string { pub fn (mut g Gen) typ(t table.Type) string {
nr_muls := table.type_nr_muls(t) nr_muls := table.type_nr_muls(t)
sym := g.table.get_type_symbol(t) sym := g.table.get_type_symbol(t)
var styp := sym.name.replace('.', '__') mut styp := sym.name.replace('.', '__')
if nr_muls > 0 { if nr_muls > 0 {
styp += strings.repeat(`*`, nr_muls) styp += strings.repeat(`*`, nr_muls)
} }
@ -249,7 +249,7 @@ pub fn (var g Gen) typ(t table.Type) string {
} }
// //
pub fn (var g Gen) write_typedef_types() { pub fn (mut g Gen) write_typedef_types() {
for typ in g.table.types { for typ in g.table.types {
match typ.kind { match typ.kind {
.alias { .alias {
@ -294,7 +294,7 @@ pub fn (var g Gen) write_typedef_types() {
} }
} }
pub fn (var g Gen) write_multi_return_types() { pub fn (mut g Gen) write_multi_return_types() {
g.definitions.writeln('// multi return structs') g.definitions.writeln('// multi return structs')
for typ in g.table.types { for typ in g.table.types {
// sym := g.table.get_type_symbol(typ) // sym := g.table.get_type_symbol(typ)
@ -315,7 +315,7 @@ pub fn (var g Gen) write_multi_return_types() {
} }
} }
pub fn (var g Gen) write_variadic_types() { pub fn (mut g Gen) write_variadic_types() {
if g.variadic_args.size > 0 { if g.variadic_args.size > 0 {
g.definitions.writeln('// variadic structs') g.definitions.writeln('// variadic structs')
} }
@ -334,7 +334,7 @@ pub fn (var g Gen) write_variadic_types() {
pub fn (g Gen) save() { pub fn (g Gen) save() {
} }
pub fn (var g Gen) write(s string) { pub fn (mut g Gen) write(s string) {
if g.indent > 0 && g.empty_line { if g.indent > 0 && g.empty_line {
g.out.write(tabs[g.indent]) g.out.write(tabs[g.indent])
// g.line_len += g.indent * 4 // g.line_len += g.indent * 4
@ -343,7 +343,7 @@ pub fn (var g Gen) write(s string) {
g.empty_line = false g.empty_line = false
} }
pub fn (var g Gen) writeln(s string) { pub fn (mut g Gen) writeln(s string) {
if g.indent > 0 && g.empty_line { if g.indent > 0 && g.empty_line {
g.out.write(tabs[g.indent]) g.out.write(tabs[g.indent])
} }
@ -351,16 +351,16 @@ pub fn (var g Gen) writeln(s string) {
g.empty_line = true g.empty_line = true
} }
pub fn (var g Gen) new_tmp_var() string { pub fn (mut g Gen) new_tmp_var() string {
g.tmp_count++ g.tmp_count++
return 'tmp$g.tmp_count' return 'tmp$g.tmp_count'
} }
pub fn (var g Gen) reset_tmp_count() { pub fn (mut g Gen) reset_tmp_count() {
g.tmp_count = 0 g.tmp_count = 0
} }
fn (var g Gen) stmts(stmts []ast.Stmt) { fn (mut g Gen) stmts(stmts []ast.Stmt) {
g.indent++ g.indent++
if g.inside_ternary { if g.inside_ternary {
g.write(' ( ') g.write(' ( ')
@ -377,7 +377,7 @@ fn (var g Gen) stmts(stmts []ast.Stmt) {
g.indent-- g.indent--
} }
fn (var g Gen) stmt(node ast.Stmt) { fn (mut g Gen) stmt(node ast.Stmt) {
g.stmt_start_pos = g.out.len g.stmt_start_pos = g.out.len
// println('cgen.stmt()') // println('cgen.stmt()')
// g.writeln('//// stmt start') // g.writeln('//// stmt start')
@ -421,7 +421,7 @@ fn (var g Gen) stmt(node ast.Stmt) {
g.comp_if(it) g.comp_if(it)
} }
ast.DeferStmt { ast.DeferStmt {
var defer_stmt := *it mut defer_stmt := *it
defer_stmt.ifdef = g.defer_ifdef defer_stmt.ifdef = g.defer_ifdef
g.defer_stmts << defer_stmt g.defer_stmts << defer_stmt
} }
@ -556,7 +556,7 @@ fn (var g Gen) stmt(node ast.Stmt) {
} }
} }
fn (var g Gen) write_defer_stmts() { fn (mut g Gen) write_defer_stmts() {
for defer_stmt in g.defer_stmts { for defer_stmt in g.defer_stmts {
g.writeln('// defer') g.writeln('// defer')
if defer_stmt.ifdef.len > 0 { if defer_stmt.ifdef.len > 0 {
@ -570,7 +570,7 @@ fn (var g Gen) write_defer_stmts() {
} }
} }
fn (var g Gen) for_in(it ast.ForInStmt) { fn (mut g Gen) for_in(it ast.ForInStmt) {
if it.is_range { if it.is_range {
// `for x in 1..10 {` // `for x in 1..10 {`
i := g.new_tmp_var() i := g.new_tmp_var()
@ -650,7 +650,7 @@ fn (var g Gen) for_in(it ast.ForInStmt) {
} }
// use instead of expr() when you need to cast to sum type (can add other casts also) // use instead of expr() when you need to cast to sum type (can add other casts also)
fn (var g Gen) expr_with_cast(expr ast.Expr, got_type, exp_type table.Type) { fn (mut g Gen) expr_with_cast(expr ast.Expr, got_type, exp_type table.Type) {
// cast to sum type // cast to sum type
if exp_type != table.void_type { if exp_type != table.void_type {
exp_sym := g.table.get_type_symbol(exp_type) exp_sym := g.table.get_type_symbol(exp_type)
@ -672,7 +672,7 @@ fn (var g Gen) expr_with_cast(expr ast.Expr, got_type, exp_type table.Type) {
g.expr(expr) g.expr(expr)
} }
fn (var g Gen) gen_assert_stmt(a ast.AssertStmt) { fn (mut g Gen) gen_assert_stmt(a ast.AssertStmt) {
g.writeln('// assert') g.writeln('// assert')
g.inside_ternary = true g.inside_ternary = true
g.write('if (') g.write('if (')
@ -680,7 +680,7 @@ fn (var g Gen) gen_assert_stmt(a ast.AssertStmt) {
g.write(')') g.write(')')
g.inside_ternary = false g.inside_ternary = false
s_assertion := a.expr.str().replace('"', "\'") s_assertion := a.expr.str().replace('"', "\'")
var mod_path := g.file.path mut mod_path := g.file.path
$if windows { $if windows {
mod_path = g.file.path.replace('\\', '\\\\') mod_path = g.file.path.replace('\\', '\\\\')
} }
@ -703,15 +703,15 @@ fn (var g Gen) gen_assert_stmt(a ast.AssertStmt) {
g.writeln('}') g.writeln('}')
} }
fn (var g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) { fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
// g.write('/*assign_stmt*/') // g.write('/*assign_stmt*/')
if assign_stmt.is_static { if assign_stmt.is_static {
g.write('static ') g.write('static ')
} }
if assign_stmt.left.len > assign_stmt.right.len { if assign_stmt.left.len > assign_stmt.right.len {
// multi return // multi return
var or_stmts := []ast.Stmt mut or_stmts := []ast.Stmt
var return_type := table.void_type mut return_type := table.void_type
match assign_stmt.right[0] { match assign_stmt.right[0] {
ast.CallExpr { ast.CallExpr {
or_stmts = it.or_block.stmts or_stmts = it.or_block.stmts
@ -753,9 +753,9 @@ fn (var g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
val := assign_stmt.right[i] val := assign_stmt.right[i]
ident_var_info := ident.var_info() ident_var_info := ident.var_info()
styp := g.typ(ident_var_info.typ) styp := g.typ(ident_var_info.typ)
var is_call := false mut is_call := false
var or_stmts := []ast.Stmt mut or_stmts := []ast.Stmt
var return_type := table.void_type mut return_type := table.void_type
match val { match val {
ast.CallExpr { ast.CallExpr {
is_call = true is_call = true
@ -776,7 +776,7 @@ fn (var g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
} }
} else { } else {
right_sym := g.table.get_type_symbol(assign_stmt.right_types[i]) right_sym := g.table.get_type_symbol(assign_stmt.right_types[i])
var is_fixed_array_init := false mut is_fixed_array_init := false
match val { match val {
ast.ArrayInit { is_fixed_array_init = it.is_fixed } ast.ArrayInit { is_fixed_array_init = it.is_fixed }
else {} else {}
@ -814,8 +814,8 @@ fn (var g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
} }
} }
fn (var g Gen) gen_clone_assignment(val ast.Expr, right_sym table.TypeSymbol, add_eq bool) bool { fn (mut g Gen) gen_clone_assignment(val ast.Expr, right_sym table.TypeSymbol, add_eq bool) bool {
var is_ident := false mut is_ident := false
match val { match val {
ast.Ident { is_ident = true } ast.Ident { is_ident = true }
ast.SelectorExpr { is_ident = true } ast.SelectorExpr { is_ident = true }
@ -841,7 +841,7 @@ fn (var g Gen) gen_clone_assignment(val ast.Expr, right_sym table.TypeSymbol, ad
return true return true
} }
fn (var g Gen) free_scope_vars(pos int) { fn (mut g Gen) free_scope_vars(pos int) {
scope := g.file.scope.innermost(pos) scope := g.file.scope.innermost(pos)
for _, obj in scope.objects { for _, obj in scope.objects {
match obj { match obj {
@ -882,7 +882,7 @@ fn (var g Gen) free_scope_vars(pos int) {
} }
} }
fn (var g Gen) expr(node ast.Expr) { fn (mut g Gen) expr(node ast.Expr) {
// println('cgen expr() line_nr=$node.pos.line_nr') // println('cgen expr() line_nr=$node.pos.line_nr')
match node { match node {
ast.ArrayInit { ast.ArrayInit {
@ -1134,7 +1134,7 @@ fn (var g Gen) expr(node ast.Expr) {
} }
} }
fn (var g Gen) typeof_expr(node ast.TypeOf) { fn (mut g Gen) typeof_expr(node ast.TypeOf) {
sym := g.table.get_type_symbol(node.expr_type) sym := g.table.get_type_symbol(node.expr_type)
if sym.kind == .sum_type { if sym.kind == .sum_type {
// When encountering a .sum_type, typeof() should be done at runtime, // When encountering a .sum_type, typeof() should be done at runtime,
@ -1150,7 +1150,7 @@ fn (var g Gen) typeof_expr(node ast.TypeOf) {
} else if sym.kind == .function { } else if sym.kind == .function {
info := sym.info as table.FnType info := sym.info as table.FnType
fn_info := info.func fn_info := info.func
var repr := 'fn (' mut repr := 'fn ('
for i, arg in fn_info.args { for i, arg in fn_info.args {
if i > 0 { if i > 0 {
repr += ', ' repr += ', '
@ -1167,18 +1167,18 @@ fn (var g Gen) typeof_expr(node ast.TypeOf) {
} }
} }
fn (var g Gen) enum_expr(node ast.Expr) { fn (mut g Gen) enum_expr(node ast.Expr) {
match node { match node {
ast.EnumVal { g.write(it.val) } ast.EnumVal { g.write(it.val) }
else { g.expr(node) } else { g.expr(node) }
} }
} }
fn (var g Gen) assign_expr(node ast.AssignExpr) { fn (mut g Gen) assign_expr(node ast.AssignExpr) {
// g.write('/*assign_expr*/') // g.write('/*assign_expr*/')
var is_call := false mut is_call := false
var or_stmts := []ast.Stmt mut or_stmts := []ast.Stmt
var return_type := table.void_type mut return_type := table.void_type
match node.val { match node.val {
ast.CallExpr { ast.CallExpr {
is_call = true is_call = true
@ -1208,7 +1208,7 @@ fn (var g Gen) assign_expr(node ast.AssignExpr) {
if table.type_is(node.right_type, .optional) { if table.type_is(node.right_type, .optional) {
g.right_is_opt = true g.right_is_opt = true
} }
var str_add := false mut str_add := false
if node.left_type == table.string_type_idx && node.op == .plus_assign { if node.left_type == table.string_type_idx && node.op == .plus_assign {
// str += str2 => `str = string_add(str, str2)` // str += str2 => `str = string_add(str, str2)`
g.expr(node.left) g.expr(node.left)
@ -1226,7 +1226,7 @@ fn (var g Gen) assign_expr(node ast.AssignExpr) {
g.is_assign_lhs = false g.is_assign_lhs = false
right_sym := g.table.get_type_symbol(node.right_type) right_sym := g.table.get_type_symbol(node.right_type)
// left_sym := g.table.get_type_symbol(node.left_type) // left_sym := g.table.get_type_symbol(node.left_type)
var cloned := false mut cloned := false
// !g.is_array_set // !g.is_array_set
if g.autofree && right_sym.kind in [.array, .string] { if g.autofree && right_sym.kind in [.array, .string] {
if g.gen_clone_assignment(node.val, right_sym, false) { if g.gen_clone_assignment(node.val, right_sym, false) {
@ -1250,7 +1250,7 @@ fn (var g Gen) assign_expr(node ast.AssignExpr) {
g.is_assign_rhs = false g.is_assign_rhs = false
} }
fn (var g Gen) infix_expr(node ast.InfixExpr) { fn (mut g Gen) infix_expr(node ast.InfixExpr) {
// println('infix_expr() op="$node.op.str()" line_nr=$node.pos.line_nr') // println('infix_expr() op="$node.op.str()" line_nr=$node.pos.line_nr')
// g.write('/*infix*/') // g.write('/*infix*/')
// if it.left_type == table.string_type_idx { // if it.left_type == table.string_type_idx {
@ -1400,7 +1400,7 @@ fn (var g Gen) infix_expr(node ast.InfixExpr) {
} }
} }
fn (var g Gen) match_expr(node ast.MatchExpr) { fn (mut g Gen) match_expr(node ast.MatchExpr) {
// println('match expr typ=$it.expr_type') // println('match expr typ=$it.expr_type')
// TODO // TODO
if node.cond_type == 0 { if node.cond_type == 0 {
@ -1414,7 +1414,7 @@ fn (var g Gen) match_expr(node ast.MatchExpr) {
// g.write('/* EM ret type=${g.typ(node.return_type)} expected_type=${g.typ(node.expected_type)} */') // g.write('/* EM ret type=${g.typ(node.return_type)} expected_type=${g.typ(node.expected_type)} */')
} }
type_sym := g.table.get_type_symbol(node.cond_type) type_sym := g.table.get_type_symbol(node.cond_type)
var tmp := '' mut tmp := ''
if type_sym.kind != .void { if type_sym.kind != .void {
tmp = g.new_tmp_var() tmp = g.new_tmp_var()
} }
@ -1504,7 +1504,7 @@ fn (var g Gen) match_expr(node ast.MatchExpr) {
g.inside_ternary = was_inside_ternary g.inside_ternary = was_inside_ternary
} }
fn (var g Gen) ident(node ast.Ident) { fn (mut g Gen) ident(node ast.Ident) {
if node.name == 'lld' { if node.name == 'lld' {
return return
} }
@ -1536,13 +1536,13 @@ fn (var g Gen) ident(node ast.Ident) {
g.write(name) g.write(name)
} }
fn (var g Gen) if_expr(node ast.IfExpr) { fn (mut g Gen) if_expr(node ast.IfExpr) {
// println('if_expr pos=$node.pos.line_nr') // println('if_expr pos=$node.pos.line_nr')
// g.writeln('/* if is_expr=$node.is_expr */') // g.writeln('/* if is_expr=$node.is_expr */')
// If expression? Assign the value to a temp var. // If expression? Assign the value to a temp var.
// Previously ?: was used, but it's too unreliable. // Previously ?: was used, but it's too unreliable.
type_sym := g.table.get_type_symbol(node.typ) type_sym := g.table.get_type_symbol(node.typ)
var tmp := '' mut tmp := ''
if type_sym.kind != .void { if type_sym.kind != .void {
tmp = g.new_tmp_var() tmp = g.new_tmp_var()
// g.writeln('$ti.name $tmp;') // g.writeln('$ti.name $tmp;')
@ -1567,7 +1567,7 @@ fn (var g Gen) if_expr(node ast.IfExpr) {
g.inside_ternary = false g.inside_ternary = false
} else { } else {
guard_ok := g.new_tmp_var() guard_ok := g.new_tmp_var()
var is_guard := false mut is_guard := false
for i, branch in node.branches { for i, branch in node.branches {
if i == 0 { if i == 0 {
match branch.cond { match branch.cond {
@ -1608,9 +1608,9 @@ fn (var g Gen) if_expr(node ast.IfExpr) {
} }
} }
fn (var g Gen) index_expr(node ast.IndexExpr) { fn (mut g Gen) index_expr(node ast.IndexExpr) {
// TODO else doesn't work with sum types // TODO else doesn't work with sum types
var is_range := false mut is_range := false
match node.index { match node.index {
ast.RangeExpr { ast.RangeExpr {
sym := g.table.get_type_symbol(node.left_type) sym := g.table.get_type_symbol(node.left_type)
@ -1677,7 +1677,7 @@ fn (var g Gen) index_expr(node ast.IndexExpr) {
g.expr(node.left) g.expr(node.left)
g.write(', ') g.write(', ')
g.expr(node.index) g.expr(node.index)
var need_wrapper := true mut need_wrapper := true
/* /*
match node.right { match node.right {
ast.EnumVal, ast.Ident { ast.EnumVal, ast.Ident {
@ -1772,7 +1772,7 @@ fn (var g Gen) index_expr(node ast.IndexExpr) {
} }
} }
fn (var g Gen) return_statement(node ast.Return) { fn (mut g Gen) return_statement(node ast.Return) {
g.write('return') g.write('return')
if g.fn_decl.name == 'main' { if g.fn_decl.name == 'main' {
g.writeln(' 0;') g.writeln(' 0;')
@ -1784,10 +1784,10 @@ fn (var g Gen) return_statement(node ast.Return) {
g.write(' ') g.write(' ')
typ_sym := g.table.get_type_symbol(g.fn_decl.return_type) typ_sym := g.table.get_type_symbol(g.fn_decl.return_type)
mr_info := typ_sym.info as table.MultiReturn mr_info := typ_sym.info as table.MultiReturn
var styp := g.typ(g.fn_decl.return_type) mut styp := g.typ(g.fn_decl.return_type)
if fn_return_is_optional { // && !table.type_is(node.types[0], .optional) && node.types[0] != if fn_return_is_optional { // && !table.type_is(node.types[0], .optional) && node.types[0] !=
styp = styp[7..] // remove 'Option_' styp = styp[7..] // remove 'Option_'
var x := styp mut x := styp
if x.ends_with('_ptr') { if x.ends_with('_ptr') {
x = x.replace('_ptr', '*') x = x.replace('_ptr', '*')
} }
@ -1812,8 +1812,8 @@ fn (var g Gen) return_statement(node ast.Return) {
// `return opt_ok(expr)` for functions that expect an optional // `return opt_ok(expr)` for functions that expect an optional
if fn_return_is_optional && !table.type_is(node.types[0], .optional) && return_sym.name != if fn_return_is_optional && !table.type_is(node.types[0], .optional) && return_sym.name !=
'Option' { 'Option' {
var is_none := false mut is_none := false
var is_error := false mut is_error := false
expr0 := node.exprs[0] expr0 := node.exprs[0]
match expr0 { match expr0 {
ast.None { ast.None {
@ -1828,7 +1828,7 @@ fn (var g Gen) return_statement(node ast.Return) {
} }
if !is_none && !is_error { if !is_none && !is_error {
styp := g.typ(g.fn_decl.return_type)[7..] // remove 'Option_' styp := g.typ(g.fn_decl.return_type)[7..] // remove 'Option_'
var x := styp mut x := styp
if x.ends_with('_ptr') { if x.ends_with('_ptr') {
x = x.replace('_ptr', '*') x = x.replace('_ptr', '*')
} }
@ -1848,7 +1848,7 @@ fn (var g Gen) return_statement(node ast.Return) {
g.writeln(';') g.writeln(';')
} }
fn (var g Gen) const_decl(node ast.ConstDecl) { fn (mut g Gen) const_decl(node ast.ConstDecl) {
for i, field in node.fields { for i, field in node.fields {
name := c_name(field.name) name := c_name(field.name)
// TODO hack. Cut the generated value and paste it into definitions. // TODO hack. Cut the generated value and paste it into definitions.
@ -1899,7 +1899,7 @@ fn (var g Gen) const_decl(node ast.ConstDecl) {
} }
} }
fn (var g Gen) const_decl_simple_define(name, val string) { fn (mut g Gen) const_decl_simple_define(name, val string) {
// Simple expressions should use a #define // Simple expressions should use a #define
// so that we don't pollute the binary with unnecessary global vars // so that we don't pollute the binary with unnecessary global vars
// Do not do this when building a module, otherwise the consts // Do not do this when building a module, otherwise the consts
@ -1908,9 +1908,9 @@ fn (var g Gen) const_decl_simple_define(name, val string) {
g.definitions.writeln(val) g.definitions.writeln(val)
} }
fn (var g Gen) struct_init(struct_init ast.StructInit) { fn (mut g Gen) struct_init(struct_init ast.StructInit) {
var info := table.Struct{} mut info := table.Struct{}
var is_struct := false mut is_struct := false
sym := g.table.get_type_symbol(struct_init.typ) sym := g.table.get_type_symbol(struct_init.typ)
if sym.kind == .struct_ { if sym.kind == .struct_ {
is_struct = true is_struct = true
@ -1927,7 +1927,7 @@ fn (var g Gen) struct_init(struct_init ast.StructInit) {
g.writeln('($styp){') g.writeln('($styp){')
} }
// var fields := []string // var fields := []string
var inited_fields := []string // TODO this is done in checker, move to ast node mut inited_fields := []string // TODO this is done in checker, move to ast node
/* /*
if struct_init.fields.len == 0 && struct_init.exprs.len > 0 { if struct_init.fields.len == 0 && struct_init.exprs.len > 0 {
// Get fields for {a,b} short syntax. Fields array wasn't set in the parser. // Get fields for {a,b} short syntax. Fields array wasn't set in the parser.
@ -1976,7 +1976,7 @@ fn (var g Gen) struct_init(struct_init ast.StructInit) {
} }
// { user | name: 'new name' } // { user | name: 'new name' }
fn (var g Gen) assoc(node ast.Assoc) { fn (mut g Gen) assoc(node ast.Assoc) {
g.writeln('// assoc') g.writeln('// assoc')
if node.typ == 0 { if node.typ == 0 {
return return
@ -2005,7 +2005,7 @@ fn (var g Gen) assoc(node ast.Assoc) {
} }
} }
fn (var g Gen) generate_array_equality_fn(ptr_typ string, styp table.Type, sym &table.TypeSymbol) { fn (mut g Gen) generate_array_equality_fn(ptr_typ string, styp table.Type, sym &table.TypeSymbol) {
g.array_fn_definitions << ptr_typ g.array_fn_definitions << ptr_typ
g.definitions.writeln('bool ${ptr_typ}_arr_eq(array_${ptr_typ} a, array_${ptr_typ} b) {') g.definitions.writeln('bool ${ptr_typ}_arr_eq(array_${ptr_typ} a, array_${ptr_typ} b) {')
g.definitions.writeln('\tif (a.len != b.len) {') g.definitions.writeln('\tif (a.len != b.len) {')
@ -2030,7 +2030,7 @@ fn verror(s string) {
util.verror('cgen error', s) util.verror('cgen error', s)
} }
fn (var g Gen) write_init_function() { fn (mut g Gen) write_init_function() {
g.writeln('void _vinit() {') g.writeln('void _vinit() {')
g.writeln('\tbuiltin_init();') g.writeln('\tbuiltin_init();')
g.writeln('\tvinit_string_literals();') g.writeln('\tvinit_string_literals();')
@ -2056,7 +2056,7 @@ fn (var g Gen) write_init_function() {
} }
} }
fn (var g Gen) write_str_fn_definitions() { fn (mut g Gen) write_str_fn_definitions() {
// _STR function can't be defined in vlib // _STR function can't be defined in vlib
g.writeln(' g.writeln('
string _STR(const char *fmt, ...) { string _STR(const char *fmt, ...) {
@ -2097,8 +2097,8 @@ const (
builtins = ['string', 'array', 'KeyValue', 'DenseArray', 'map', 'Option'] builtins = ['string', 'array', 'KeyValue', 'DenseArray', 'map', 'Option']
) )
fn (var g Gen) write_builtin_types() { fn (mut g Gen) write_builtin_types() {
var builtin_types := []table.TypeSymbol // builtin types mut builtin_types := []table.TypeSymbol // builtin types
// builtin types need to be on top // builtin types need to be on top
// everything except builtin will get sorted // everything except builtin will get sorted
for builtin_name in builtins { for builtin_name in builtins {
@ -2110,8 +2110,8 @@ fn (var g Gen) write_builtin_types() {
// C struct definitions, ordered // C struct definitions, ordered
// Sort the types, make sure types that are referenced by other types // Sort the types, make sure types that are referenced by other types
// are added before them. // are added before them.
fn (var g Gen) write_sorted_types() { fn (mut g Gen) write_sorted_types() {
var types := []table.TypeSymbol // structs that need to be sorted mut types := []table.TypeSymbol // structs that need to be sorted
for typ in g.table.types { for typ in g.table.types {
if !(typ.name in builtins) { if !(typ.name in builtins) {
types << typ types << typ
@ -2125,7 +2125,7 @@ fn (var g Gen) write_sorted_types() {
g.write_types(types_sorted) g.write_types(types_sorted)
} }
fn (var g Gen) write_types(types []table.TypeSymbol) { fn (mut g Gen) write_types(types []table.TypeSymbol) {
for typ in types { for typ in types {
if typ.name.starts_with('C.') { if typ.name.starts_with('C.') {
continue continue
@ -2169,7 +2169,7 @@ int typ;
// .array_fixed { // .array_fixed {
styp := typ.name.replace('.', '__') styp := typ.name.replace('.', '__')
// array_fixed_char_300 => char x[300] // array_fixed_char_300 => char x[300]
var fixed := styp[12..] mut fixed := styp[12..]
len := styp.after('_') len := styp.after('_')
fixed = fixed[..fixed.len - len.len - 1] fixed = fixed[..fixed.len - len.len - 1]
g.definitions.writeln('typedef $fixed $styp [$len];') g.definitions.writeln('typedef $fixed $styp [$len];')
@ -2182,16 +2182,16 @@ int typ;
// sort structs by dependant fields // sort structs by dependant fields
fn (g Gen) sort_structs(typesa []table.TypeSymbol) []table.TypeSymbol { fn (g Gen) sort_structs(typesa []table.TypeSymbol) []table.TypeSymbol {
var dep_graph := depgraph.new_dep_graph() mut dep_graph := depgraph.new_dep_graph()
// types name list // types name list
var type_names := []string mut type_names := []string
for typ in typesa { for typ in typesa {
type_names << typ.name type_names << typ.name
} }
// loop over types // loop over types
for t in typesa { for t in typesa {
// create list of deps // create list of deps
var field_deps := []string mut field_deps := []string
match t.info { match t.info {
table.ArrayFixed { table.ArrayFixed {
dep := g.table.get_type_symbol(it.elem_type).name dep := g.table.get_type_symbol(it.elem_type).name
@ -2224,14 +2224,14 @@ fn (g Gen) sort_structs(typesa []table.TypeSymbol) []table.TypeSymbol {
'\nif you feel this is an error, please create a new issue here: https://github.com/vlang/v/issues and tag @joe-conigliaro') '\nif you feel this is an error, please create a new issue here: https://github.com/vlang/v/issues and tag @joe-conigliaro')
} }
// sort types // sort types
var types_sorted := []table.TypeSymbol mut types_sorted := []table.TypeSymbol
for node in dep_graph_sorted.nodes { for node in dep_graph_sorted.nodes {
types_sorted << g.table.types[g.table.type_idxs[node.name]] types_sorted << g.table.types[g.table.type_idxs[node.name]]
} }
return types_sorted return types_sorted
} }
fn (var g Gen) string_inter_literal(node ast.StringInterLiteral) { fn (mut g Gen) string_inter_literal(node ast.StringInterLiteral) {
g.write('_STR("') g.write('_STR("')
// Build the string with % // Build the string with %
for i, val in node.vals { for i, val in node.vals {
@ -2353,7 +2353,7 @@ fn (var g Gen) string_inter_literal(node ast.StringInterLiteral) {
} }
// `nums.filter(it % 2 == 0)` // `nums.filter(it % 2 == 0)`
fn (var g Gen) gen_filter(node ast.CallExpr) { fn (mut g Gen) gen_filter(node ast.CallExpr) {
tmp := g.new_tmp_var() tmp := g.new_tmp_var()
s := g.out.after(g.stmt_start_pos) // the already generated part of current statement s := g.out.after(g.stmt_start_pos) // the already generated part of current statement
g.out.go_back(s.len) g.out.go_back(s.len)
@ -2381,7 +2381,7 @@ fn (var g Gen) gen_filter(node ast.CallExpr) {
g.write(tmp) g.write(tmp)
} }
fn (var g Gen) insert_before(s string) { fn (mut g Gen) insert_before(s string) {
cur_line := g.out.after(g.stmt_start_pos) cur_line := g.out.after(g.stmt_start_pos)
g.out.go_back(cur_line.len) g.out.go_back(cur_line.len)
g.writeln(s) g.writeln(s)
@ -2392,7 +2392,7 @@ fn (var g Gen) insert_before(s string) {
// If the user is not using the optional return value. We need to pass a temp var // If the user is not using the optional return value. We need to pass a temp var
// to access its fields (`.ok`, `.error` etc) // to access its fields (`.ok`, `.error` etc)
// `os.cp(...)` => `Option bool tmp = os__cp(...); if (!tmp.ok) { ... }` // `os.cp(...)` => `Option bool tmp = os__cp(...); if (!tmp.ok) { ... }`
fn (var g Gen) or_block(var_name string, stmts []ast.Stmt, return_type table.Type) { fn (mut g Gen) or_block(var_name string, stmts []ast.Stmt, return_type table.Type) {
mr_styp := g.typ(return_type) mr_styp := g.typ(return_type)
mr_styp2 := mr_styp[7..] // remove Option_ mr_styp2 := mr_styp[7..] // remove Option_
g.writeln(';') // or') g.writeln(';') // or')
@ -2415,9 +2415,9 @@ fn (var g Gen) or_block(var_name string, stmts []ast.Stmt, return_type table.Typ
g.write('}') g.write('}')
} }
fn (var g Gen) type_of_last_statement(stmts []ast.Stmt) (string, string) { fn (mut g Gen) type_of_last_statement(stmts []ast.Stmt) (string, string) {
var last_type := '' mut last_type := ''
var last_expr_result_type := '' mut last_expr_result_type := ''
if stmts.len > 0 { if stmts.len > 0 {
last_stmt := stmts[stmts.len - 1] last_stmt := stmts[stmts.len - 1]
last_type = typeof(last_stmt) last_type = typeof(last_stmt)
@ -2443,7 +2443,7 @@ fn (var g Gen) type_of_last_statement(stmts []ast.Stmt) (string, string) {
return last_type, last_expr_result_type return last_type, last_expr_result_type
} }
fn (var g Gen) type_of_call_expr(node ast.Expr) string { fn (mut g Gen) type_of_call_expr(node ast.Expr) string {
match node { match node {
ast.CallExpr { return g.typ(it.return_type) } ast.CallExpr { return g.typ(it.return_type) }
else { return typeof(node) } else { return typeof(node) }
@ -2452,7 +2452,7 @@ fn (var g Gen) type_of_call_expr(node ast.Expr) string {
} }
// `a in [1,2,3]` => `a == 1 || a == 2 || a == 3` // `a in [1,2,3]` => `a == 1 || a == 2 || a == 3`
fn (var g Gen) in_optimization(left ast.Expr, right ast.ArrayInit) { fn (mut g Gen) in_optimization(left ast.Expr, right ast.ArrayInit) {
is_str := right.elem_type == table.string_type is_str := right.elem_type == table.string_type
for i, array_expr in right.exprs { for i, array_expr in right.exprs {
if is_str { if is_str {
@ -2599,7 +2599,7 @@ fn (g Gen) type_default(typ table.Type) string {
*/ */
} }
pub fn (var g Gen) write_tests_main() { pub fn (mut g Gen) write_tests_main() {
g.definitions.writeln('int g_test_oks = 0;') g.definitions.writeln('int g_test_oks = 0;')
g.definitions.writeln('int g_test_fails = 0;') g.definitions.writeln('int g_test_fails = 0;')
$if windows { $if windows {
@ -2636,9 +2636,9 @@ pub fn (var g Gen) write_tests_main() {
} }
fn (g Gen) get_all_test_function_names() []string { fn (g Gen) get_all_test_function_names() []string {
var tfuncs := []string mut tfuncs := []string
var tsuite_begin := '' mut tsuite_begin := ''
var tsuite_end := '' mut tsuite_end := ''
for _, f in g.table.fns { for _, f in g.table.fns {
if f.name == 'testsuite_begin' { if f.name == 'testsuite_begin' {
tsuite_begin = f.name tsuite_begin = f.name
@ -2667,7 +2667,7 @@ fn (g Gen) get_all_test_function_names() []string {
continue continue
} }
} }
var all_tfuncs := []string mut all_tfuncs := []string
if tsuite_begin.len > 0 { if tsuite_begin.len > 0 {
all_tfuncs << tsuite_begin all_tfuncs << tsuite_begin
} }
@ -2675,7 +2675,7 @@ fn (g Gen) get_all_test_function_names() []string {
if tsuite_end.len > 0 { if tsuite_end.len > 0 {
all_tfuncs << tsuite_end all_tfuncs << tsuite_end
} }
var all_tfuncs_c := []string mut all_tfuncs_c := []string
for f in all_tfuncs { for f in all_tfuncs {
all_tfuncs_c << f.replace('.', '__') all_tfuncs_c << f.replace('.', '__')
} }
@ -2686,7 +2686,7 @@ fn (g Gen) is_importing_os() bool {
return 'os' in g.table.imports return 'os' in g.table.imports
} }
fn (var g Gen) comp_if(it ast.CompIf) { fn (mut g Gen) comp_if(it ast.CompIf) {
ifdef := comp_if_to_ifdef(it.val) ifdef := comp_if_to_ifdef(it.val)
if it.is_not { if it.is_not {
g.writeln('\n#ifndef ' + ifdef) g.writeln('\n#ifndef ' + ifdef)
@ -2718,12 +2718,12 @@ fn (var g Gen) comp_if(it ast.CompIf) {
g.writeln('\n#endif') g.writeln('\n#endif')
} }
fn (var g Gen) go_stmt(node ast.GoStmt) { fn (mut g Gen) go_stmt(node ast.GoStmt) {
tmp := g.new_tmp_var() tmp := g.new_tmp_var()
// x := node.call_expr as ast.CallEpxr // TODO // x := node.call_expr as ast.CallEpxr // TODO
match node.call_expr { match node.call_expr {
ast.CallExpr { ast.CallExpr {
var name := it.name.replace('.', '__') mut name := it.name.replace('.', '__')
if it.is_method { if it.is_method {
receiver_sym := g.table.get_type_symbol(it.receiver_type) receiver_sym := g.table.get_type_symbol(it.receiver_type)
name = receiver_sym.name + '_' + name name = receiver_sym.name + '_' + name
@ -2788,14 +2788,14 @@ fn (var g Gen) go_stmt(node ast.GoStmt) {
} }
} }
fn (var g Gen) is_expr(node ast.InfixExpr) { fn (mut g Gen) is_expr(node ast.InfixExpr) {
g.expr(node.left) g.expr(node.left)
g.write('.typ == ') g.write('.typ == ')
g.expr(node.right) g.expr(node.right)
} }
// already generated styp, reuse it // already generated styp, reuse it
fn (var g Gen) gen_str_for_type(sym table.TypeSymbol, styp string) { fn (mut g Gen) gen_str_for_type(sym table.TypeSymbol, styp string) {
if sym.has_method('str') || styp in g.str_types { if sym.has_method('str') || styp in g.str_types {
return return
} }
@ -2809,9 +2809,9 @@ fn (var g Gen) gen_str_for_type(sym table.TypeSymbol, styp string) {
} }
} }
fn (var g Gen) gen_str_default(sym table.TypeSymbol, styp string) { fn (mut g Gen) gen_str_default(sym table.TypeSymbol, styp string) {
var convertor := '' mut convertor := ''
var typename := '' mut typename := ''
if sym.parent_idx in table.integer_type_idxs { if sym.parent_idx in table.integer_type_idxs {
convertor = 'int' convertor = 'int'
typename = 'int' typename = 'int'
@ -2839,7 +2839,7 @@ fn (var g Gen) gen_str_default(sym table.TypeSymbol, styp string) {
g.definitions.writeln('}') g.definitions.writeln('}')
} }
fn (var g Gen) gen_str_for_enum(info table.Enum, styp string) { fn (mut g Gen) gen_str_for_enum(info table.Enum, styp string) {
s := styp.replace('.', '__') s := styp.replace('.', '__')
g.definitions.write('string ${s}_str($styp it) {\n\tswitch(it) {\n') g.definitions.write('string ${s}_str($styp it) {\n\tswitch(it) {\n')
for i, val in info.vals { for i, val in info.vals {
@ -2848,7 +2848,7 @@ fn (var g Gen) gen_str_for_enum(info table.Enum, styp string) {
g.definitions.write('\t\tdefault: return tos3("unknown enum value"); } }\n') g.definitions.write('\t\tdefault: return tos3("unknown enum value"); } }\n')
} }
fn (var g Gen) gen_str_for_struct(info table.Struct, styp string) { fn (mut g Gen) gen_str_for_struct(info table.Struct, styp string) {
// TODO: short it if possible // TODO: short it if possible
// generates all definitions of substructs // generates all definitions of substructs
for i, field in info.fields { for i, field in info.fields {
@ -2892,7 +2892,7 @@ fn (var g Gen) gen_str_for_struct(info table.Struct, styp string) {
g.definitions.writeln(', indents.len, indents.str);\n}') g.definitions.writeln(', indents.len, indents.str);\n}')
} }
fn (var g Gen) gen_str_for_array(info table.Array, styp string) { fn (mut g Gen) gen_str_for_array(info table.Array, styp string) {
s := styp.replace('.', '__') s := styp.replace('.', '__')
sym := g.table.get_type_symbol(info.elem_type) sym := g.table.get_type_symbol(info.elem_type)
field_styp := g.typ(info.elem_type) field_styp := g.typ(info.elem_type)

View File

@ -9,7 +9,7 @@ import v.scanner
import v.token import v.token
import v.util import v.util
pub fn (var p Parser) call_expr(is_c, is_js bool, mod string) ast.CallExpr { pub fn (mut p Parser) call_expr(is_c, is_js bool, mod string) ast.CallExpr {
first_pos := p.tok.position() first_pos := p.tok.position()
tok := p.tok tok := p.tok
name := p.check_name() name := p.check_name()
@ -31,8 +31,8 @@ pub fn (var p Parser) call_expr(is_c, is_js bool, mod string) ast.CallExpr {
pos: first_pos.pos pos: first_pos.pos
len: last_pos.pos - first_pos.pos + last_pos.len len: last_pos.pos - first_pos.pos + last_pos.len
} }
var or_stmts := []ast.Stmt mut or_stmts := []ast.Stmt
var is_or_block_used := false mut is_or_block_used := false
if p.tok.kind == .key_orelse { if p.tok.kind == .key_orelse {
p.next() p.next()
p.open_scope() p.open_scope()
@ -63,10 +63,10 @@ pub fn (var p Parser) call_expr(is_c, is_js bool, mod string) ast.CallExpr {
return node return node
} }
pub fn (var p Parser) call_args() []ast.CallArg { pub fn (mut p Parser) call_args() []ast.CallArg {
var args := []ast.CallArg mut args := []ast.CallArg
for p.tok.kind != .rpar { for p.tok.kind != .rpar {
var is_mut := false mut is_mut := false
if p.tok.kind == .key_mut { if p.tok.kind == .key_mut {
p.check(.key_mut) p.check(.key_mut)
is_mut = true is_mut = true
@ -83,7 +83,7 @@ pub fn (var p Parser) call_args() []ast.CallArg {
return args return args
} }
fn (var p Parser) fn_decl() ast.FnDecl { fn (mut p Parser) fn_decl() ast.FnDecl {
// p.table.clear_vars() // p.table.clear_vars()
start_pos := p.tok.position() start_pos := p.tok.position()
p.open_scope() p.open_scope()
@ -101,11 +101,11 @@ fn (var p Parser) fn_decl() ast.FnDecl {
p.check(.dot) p.check(.dot)
} }
// Receiver? // Receiver?
var rec_name := '' mut rec_name := ''
var is_method := false mut is_method := false
var rec_type := table.void_type mut rec_type := table.void_type
var rec_mut := false mut rec_mut := false
var args := []table.Arg mut args := []table.Arg
if p.tok.kind == .lpar { if p.tok.kind == .lpar {
p.next() // ( p.next() // (
is_method = true is_method = true
@ -134,7 +134,7 @@ fn (var p Parser) fn_decl() ast.FnDecl {
} }
p.check(.rpar) p.check(.rpar)
} }
var name := '' mut name := ''
if p.tok.kind == .name { if p.tok.kind == .name {
// TODO high order fn // TODO high order fn
name = p.check_name() name = p.check_name()
@ -165,16 +165,16 @@ fn (var p Parser) fn_decl() ast.FnDecl {
typ: arg.typ typ: arg.typ
}) })
} }
var end_pos := p.prev_tok.position() mut end_pos := p.prev_tok.position()
// Return type // Return type
var return_type := table.void_type mut return_type := table.void_type
if p.tok.kind.is_start_of_type() { if p.tok.kind.is_start_of_type() {
end_pos = p.tok.position() end_pos = p.tok.position()
return_type = p.parse_type() return_type = p.parse_type()
} }
// Register // Register
if is_method { if is_method {
var type_sym := p.table.get_type_symbol(rec_type) mut type_sym := p.table.get_type_symbol(rec_type)
// p.warn('reg method $type_sym.name . $name ()') // p.warn('reg method $type_sym.name . $name ()')
type_sym.register_method(table.Fn{ type_sym.register_method(table.Fn{
name: name name: name
@ -207,7 +207,7 @@ fn (var p Parser) fn_decl() ast.FnDecl {
}) })
} }
// Body // Body
var stmts := []ast.Stmt mut stmts := []ast.Stmt
no_body := p.tok.kind != .lcbr no_body := p.tok.kind != .lcbr
if p.tok.kind == .lcbr { if p.tok.kind == .lcbr {
stmts = p.parse_block() stmts = p.parse_block()
@ -236,7 +236,7 @@ fn (var p Parser) fn_decl() ast.FnDecl {
} }
} }
fn (var p Parser) anon_fn() ast.AnonFn { fn (mut p Parser) anon_fn() ast.AnonFn {
pos := p.tok.position() pos := p.tok.position()
p.open_scope() p.open_scope()
p.check(.key_fn) p.check(.key_fn)
@ -248,11 +248,11 @@ fn (var p Parser) anon_fn() ast.AnonFn {
typ: arg.typ typ: arg.typ
}) })
} }
var return_type := table.void_type mut return_type := table.void_type
if p.tok.kind.is_start_of_type() { if p.tok.kind.is_start_of_type() {
return_type = p.parse_type() return_type = p.parse_type()
} }
var stmts := []ast.Stmt mut stmts := []ast.Stmt
no_body := p.tok.kind != .lcbr no_body := p.tok.kind != .lcbr
if p.tok.kind == .lcbr { if p.tok.kind == .lcbr {
stmts = p.parse_block() stmts = p.parse_block()
@ -282,16 +282,16 @@ fn (var p Parser) anon_fn() ast.AnonFn {
} }
} }
fn (var p Parser) fn_args() ([]table.Arg, bool) { fn (mut p Parser) fn_args() ([]table.Arg, bool) {
p.check(.lpar) p.check(.lpar)
var args := []table.Arg mut args := []table.Arg
var is_variadic := false mut is_variadic := false
// `int, int, string` (no names, just types) // `int, int, string` (no names, just types)
types_only := p.tok.kind in [.amp, .and] || (p.peek_tok.kind == .comma && p.table.known_type(p.tok.lit)) || types_only := p.tok.kind in [.amp, .and] || (p.peek_tok.kind == .comma && p.table.known_type(p.tok.lit)) ||
p.peek_tok.kind == .rpar p.peek_tok.kind == .rpar
if types_only { if types_only {
// p.warn('types only') // p.warn('types only')
var arg_no := 1 mut arg_no := 1
for p.tok.kind != .rpar { for p.tok.kind != .rpar {
arg_name := 'arg_$arg_no' arg_name := 'arg_$arg_no'
is_mut := p.tok.kind == .key_mut is_mut := p.tok.kind == .key_mut
@ -302,7 +302,7 @@ fn (var p Parser) fn_args() ([]table.Arg, bool) {
p.check(.ellipsis) p.check(.ellipsis)
is_variadic = true is_variadic = true
} }
var arg_type := p.parse_type() mut arg_type := p.parse_type()
if is_variadic { if is_variadic {
arg_type = table.type_set(arg_type, .variadic) arg_type = table.type_set(arg_type, .variadic)
} }
@ -321,7 +321,7 @@ fn (var p Parser) fn_args() ([]table.Arg, bool) {
} }
} else { } else {
for p.tok.kind != .rpar { for p.tok.kind != .rpar {
var arg_names := [p.check_name()] mut arg_names := [p.check_name()]
// `a, b, c int` // `a, b, c int`
for p.tok.kind == .comma { for p.tok.kind == .comma {
p.check(.comma) p.check(.comma)
@ -335,7 +335,7 @@ fn (var p Parser) fn_args() ([]table.Arg, bool) {
p.check(.ellipsis) p.check(.ellipsis)
is_variadic = true is_variadic = true
} }
var typ := p.parse_type() mut typ := p.parse_type()
if is_variadic { if is_variadic {
typ = table.type_set(typ, .variadic) typ = table.type_set(typ, .variadic)
} }

View File

@ -46,7 +46,7 @@ mut:
// for tests // for tests
pub fn parse_stmt(text string, table &table.Table, scope &ast.Scope) ast.Stmt { pub fn parse_stmt(text string, table &table.Table, scope &ast.Scope) ast.Stmt {
s := scanner.new_scanner(text, .skip_comments) s := scanner.new_scanner(text, .skip_comments)
var p := Parser{ mut p := Parser{
scanner: s scanner: s
table: table table: table
pref: &pref.Preferences{} pref: &pref.Preferences{}
@ -66,8 +66,8 @@ pub fn parse_file(path string, table &table.Table, comments_mode scanner.Comment
// text := os.read_file(path) or { // text := os.read_file(path) or {
// panic(err) // panic(err)
// } // }
var stmts := []ast.Stmt mut stmts := []ast.Stmt
var p := Parser{ mut p := Parser{
scanner: scanner.new_scanner_file(path, comments_mode) scanner: scanner.new_scanner_file(path, comments_mode)
table: table table: table
file_name: path file_name: path
@ -82,12 +82,12 @@ pub fn parse_file(path string, table &table.Table, comments_mode scanner.Comment
// comments_mode: comments_mode // comments_mode: comments_mode
p.read_first_token() p.read_first_token()
for p.tok.kind == .comment { for p.tok.kind == .comment {
var stmt := ast.Stmt{} // TODO sum type << bug mut stmt := ast.Stmt{} // TODO sum type << bug
com := p.comment() com := p.comment()
stmt = com stmt = com
stmts << stmt stmts << stmt
} }
var mstmt := ast.Stmt{} mut mstmt := ast.Stmt{}
module_decl := p.module_decl() module_decl := p.module_decl()
mstmt = module_decl mstmt = module_decl
stmts << mstmt stmts << mstmt
@ -164,7 +164,7 @@ pub fn parse_files(paths []string, table &table.Table, pref &pref.Preferences, g
return q.parsed_ast_files return q.parsed_ast_files
*/ */
// /////////////// // ///////////////
var files := []ast.File mut files := []ast.File
for path in paths { for path in paths {
// println('parse_files $path') // println('parse_files $path')
files << parse_file(path, table, .skip_comments, pref, global_scope) files << parse_file(path, table, .skip_comments, pref, global_scope)
@ -178,26 +178,26 @@ pub fn (p &Parser) init_parse_fns() {
println('') println('')
} }
pub fn (var p Parser) read_first_token() { pub fn (mut p Parser) read_first_token() {
// need to call next() twice to get peek token and current token // need to call next() twice to get peek token and current token
p.next() p.next()
p.next() p.next()
} }
pub fn (var p Parser) open_scope() { pub fn (mut p Parser) open_scope() {
p.scope = &ast.Scope{ p.scope = &ast.Scope{
parent: p.scope parent: p.scope
start_pos: p.tok.pos start_pos: p.tok.pos
} }
} }
pub fn (var p Parser) close_scope() { pub fn (mut p Parser) close_scope() {
p.scope.end_pos = p.tok.pos p.scope.end_pos = p.tok.pos
p.scope.parent.children << p.scope p.scope.parent.children << p.scope
p.scope = p.scope.parent p.scope = p.scope.parent
} }
pub fn (var p Parser) parse_block() []ast.Stmt { pub fn (mut p Parser) parse_block() []ast.Stmt {
p.open_scope() p.open_scope()
// println('parse block') // println('parse block')
stmts := p.parse_block_no_scope() stmts := p.parse_block_no_scope()
@ -206,9 +206,9 @@ pub fn (var p Parser) parse_block() []ast.Stmt {
return stmts return stmts
} }
pub fn (var p Parser) parse_block_no_scope() []ast.Stmt { pub fn (mut p Parser) parse_block_no_scope() []ast.Stmt {
p.check(.lcbr) p.check(.lcbr)
var stmts := []ast.Stmt mut stmts := []ast.Stmt
if p.tok.kind != .rcbr { if p.tok.kind != .rcbr {
for { for {
stmts << p.stmt() stmts << p.stmt()
@ -228,7 +228,7 @@ fn (p mut Parser) next_with_comment() {
p.peek_tok = p.scanner.scan() p.peek_tok = p.scanner.scan()
} }
*/ */
fn (var p Parser) next() { fn (mut p Parser) next() {
p.prev_tok = p.tok p.prev_tok = p.tok
p.tok = p.peek_tok p.tok = p.peek_tok
p.peek_tok = p.scanner.scan() p.peek_tok = p.scanner.scan()
@ -240,7 +240,7 @@ fn (var p Parser) next() {
*/ */
} }
fn (var p Parser) check(expected token.Kind) { fn (mut p Parser) check(expected token.Kind) {
// for p.tok.kind in [.line_comment, .mline_comment] { // for p.tok.kind in [.line_comment, .mline_comment] {
// p.next() // p.next()
// } // }
@ -250,13 +250,13 @@ fn (var p Parser) check(expected token.Kind) {
p.next() p.next()
} }
fn (var p Parser) check_name() string { fn (mut p Parser) check_name() string {
name := p.tok.lit name := p.tok.lit
p.check(.name) p.check(.name)
return name return name
} }
pub fn (var p Parser) top_stmt() ast.Stmt { pub fn (mut p Parser) top_stmt() ast.Stmt {
match p.tok.kind { match p.tok.kind {
.key_pub { .key_pub {
match p.peek_tok.kind { match p.peek_tok.kind {
@ -339,14 +339,14 @@ pub fn (var p Parser) top_stmt() ast.Stmt {
} }
// TODO [if vfmt] // TODO [if vfmt]
pub fn (var p Parser) check_comment() ast.Comment { pub fn (mut p Parser) check_comment() ast.Comment {
if p.tok.kind == .comment { if p.tok.kind == .comment {
return p.comment() return p.comment()
} }
return ast.Comment{} return ast.Comment{}
} }
pub fn (var p Parser) comment() ast.Comment { pub fn (mut p Parser) comment() ast.Comment {
pos := p.tok.position() pos := p.tok.position()
text := p.tok.lit text := p.tok.lit
p.next() p.next()
@ -357,7 +357,7 @@ pub fn (var p Parser) comment() ast.Comment {
} }
} }
pub fn (var p Parser) stmt() ast.Stmt { pub fn (mut p Parser) stmt() ast.Stmt {
p.is_stmt_ident = p.tok.kind == .name p.is_stmt_ident = p.tok.kind == .name
match p.tok.kind { match p.tok.kind {
.lcbr { .lcbr {
@ -456,12 +456,12 @@ pub fn (var p Parser) stmt() ast.Stmt {
} }
} }
fn (var p Parser) attribute() ast.Attr { fn (mut p Parser) attribute() ast.Attr {
p.check(.lsbr) p.check(.lsbr)
if p.tok.kind == .key_if { if p.tok.kind == .key_if {
p.next() p.next()
} }
var name := p.check_name() mut name := p.check_name()
if p.tok.kind == .colon { if p.tok.kind == .colon {
p.next() p.next()
if p.tok.kind == .name { if p.tok.kind == .name {
@ -508,7 +508,7 @@ pub fn (p &Parser) warn(s string) {
} }
pub fn (p &Parser) error_with_pos(s string, pos token.Position) { pub fn (p &Parser) error_with_pos(s string, pos token.Position) {
var kind := 'error:' mut kind := 'error:'
if p.pref.is_verbose { if p.pref.is_verbose {
print_backtrace() print_backtrace()
kind = 'parser error:' kind = 'parser error:'
@ -523,10 +523,10 @@ pub fn (p &Parser) warn_with_pos(s string, pos token.Position) {
eprintln(ferror) eprintln(ferror)
} }
pub fn (var p Parser) parse_ident(is_c, is_js bool) ast.Ident { pub fn (mut p Parser) parse_ident(is_c, is_js bool) ast.Ident {
// p.warn('name ') // p.warn('name ')
pos := p.tok.position() pos := p.tok.position()
var name := p.check_name() mut name := p.check_name()
if name == '_' { if name == '_' {
return ast.Ident{ return ast.Ident{
name: '_' name: '_'
@ -537,7 +537,7 @@ pub fn (var p Parser) parse_ident(is_c, is_js bool) ast.Ident {
if p.expr_mod.len > 0 { if p.expr_mod.len > 0 {
name = '${p.expr_mod}.$name' name = '${p.expr_mod}.$name'
} }
var ident := ast.Ident{ mut ident := ast.Ident{
kind: .unresolved kind: .unresolved
name: name name: name
is_c: is_c is_c: is_c
@ -548,8 +548,8 @@ pub fn (var p Parser) parse_ident(is_c, is_js bool) ast.Ident {
return ident return ident
} }
pub fn (var p Parser) name_expr() ast.Expr { pub fn (mut p Parser) name_expr() ast.Expr {
var node := ast.Expr{} mut node := ast.Expr{}
if p.inside_is { if p.inside_is {
p.inside_is = false p.inside_is = false
// get type position before moving to next // get type position before moving to next
@ -561,7 +561,7 @@ pub fn (var p Parser) name_expr() ast.Expr {
} }
is_c := p.tok.lit == 'C' is_c := p.tok.lit == 'C'
is_js := p.tok.lit == 'JS' is_js := p.tok.lit == 'JS'
var mod := '' mut mod := ''
// p.warn('resetting') // p.warn('resetting')
p.expr_mod = '' p.expr_mod = ''
// `map[string]int` initialization // `map[string]int` initialization
@ -593,7 +593,7 @@ pub fn (var p Parser) name_expr() ast.Expr {
// p.warn('name expr $p.tok.lit $p.peek_tok.str()') // p.warn('name expr $p.tok.lit $p.peek_tok.str()')
// fn call or type cast // fn call or type cast
if p.peek_tok.kind == .lpar { if p.peek_tok.kind == .lpar {
var name := p.tok.lit mut name := p.tok.lit
if mod.len > 0 { if mod.len > 0 {
name = '${mod}.$name' name = '${mod}.$name'
} }
@ -604,15 +604,15 @@ pub fn (var p Parser) name_expr() ast.Expr {
'C.sigaction' 'C.sigaction'
]) { ]) {
// TODO handle C.stat() // TODO handle C.stat()
var to_typ := p.parse_type() mut to_typ := p.parse_type()
if p.is_amp { if p.is_amp {
// Handle `&Foo(0)` // Handle `&Foo(0)`
to_typ = table.type_to_ptr(to_typ) to_typ = table.type_to_ptr(to_typ)
} }
p.check(.lpar) p.check(.lpar)
var expr := ast.Expr{} mut expr := ast.Expr{}
var arg := ast.Expr{} mut arg := ast.Expr{}
var has_arg := false mut has_arg := false
expr = p.expr(0) expr = p.expr(0)
// TODO, string(b, len) // TODO, string(b, len)
if p.tok.kind == .comma && table.type_idx(to_typ) == table.string_type_idx { if p.tok.kind == .comma && table.type_idx(to_typ) == table.string_type_idx {
@ -640,7 +640,7 @@ pub fn (var p Parser) name_expr() ast.Expr {
return p.struct_init(false) // short_syntax: false return p.struct_init(false) // short_syntax: false
} else if p.peek_tok.kind == .dot && (p.tok.lit[0].is_capital() && !known_var) { } else if p.peek_tok.kind == .dot && (p.tok.lit[0].is_capital() && !known_var) {
// `Color.green` // `Color.green`
var enum_name := p.check_name() mut enum_name := p.check_name()
if mod != '' { if mod != '' {
enum_name = mod + '.' + enum_name enum_name = mod + '.' + enum_name
} else { } else {
@ -658,7 +658,7 @@ pub fn (var p Parser) name_expr() ast.Expr {
mod: mod mod: mod
} }
} else { } else {
var ident := ast.Ident{} mut ident := ast.Ident{}
ident = p.parse_ident(is_c, is_js) ident = p.parse_ident(is_c, is_js)
node = ident node = ident
} }
@ -666,10 +666,10 @@ pub fn (var p Parser) name_expr() ast.Expr {
return node return node
} }
fn (var p Parser) index_expr(left ast.Expr) ast.IndexExpr { fn (mut p Parser) index_expr(left ast.Expr) ast.IndexExpr {
// left == `a` in `a[0]` // left == `a` in `a[0]`
p.next() // [ p.next() // [
var has_low := true mut has_low := true
if p.tok.kind == .dotdot { if p.tok.kind == .dotdot {
has_low = false has_low = false
// [..end] // [..end]
@ -687,11 +687,11 @@ fn (var p Parser) index_expr(left ast.Expr) ast.IndexExpr {
} }
} }
expr := p.expr(0) // `[expr]` or `[expr..]` expr := p.expr(0) // `[expr]` or `[expr..]`
var has_high := false mut has_high := false
if p.tok.kind == .dotdot { if p.tok.kind == .dotdot {
// [start..end] or [start..] // [start..end] or [start..]
p.check(.dotdot) p.check(.dotdot)
var high := ast.Expr{} mut high := ast.Expr{}
if p.tok.kind != .rsbr { if p.tok.kind != .rsbr {
has_high = true has_high = true
high = p.expr(0) high = p.expr(0)
@ -717,15 +717,15 @@ fn (var p Parser) index_expr(left ast.Expr) ast.IndexExpr {
} }
} }
fn (var p Parser) filter() { fn (mut p Parser) filter() {
p.scope.register('it', ast.Var{ p.scope.register('it', ast.Var{
name: 'it' name: 'it'
}) })
} }
fn (var p Parser) dot_expr(left ast.Expr) ast.Expr { fn (mut p Parser) dot_expr(left ast.Expr) ast.Expr {
p.next() p.next()
var name_pos := p.tok.position() mut name_pos := p.tok.position()
field_name := p.check_name() field_name := p.check_name()
is_filter := field_name in ['filter', 'map'] is_filter := field_name in ['filter', 'map']
if is_filter { if is_filter {
@ -742,8 +742,8 @@ fn (var p Parser) dot_expr(left ast.Expr) ast.Expr {
p.next() p.next()
args := p.call_args() args := p.call_args()
p.check(.rpar) p.check(.rpar)
var or_stmts := []ast.Stmt mut or_stmts := []ast.Stmt
var is_or_block_used := false mut is_or_block_used := false
if p.tok.kind == .key_orelse { if p.tok.kind == .key_orelse {
p.next() p.next()
p.open_scope() p.open_scope()
@ -776,7 +776,7 @@ fn (var p Parser) dot_expr(left ast.Expr) ast.Expr {
is_used: is_or_block_used is_used: is_or_block_used
} }
} }
var node := ast.Expr{} mut node := ast.Expr{}
node = mcall_expr node = mcall_expr
if is_filter { if is_filter {
p.close_scope() p.close_scope()
@ -788,7 +788,7 @@ fn (var p Parser) dot_expr(left ast.Expr) ast.Expr {
field: field_name field: field_name
pos: name_pos pos: name_pos
} }
var node := ast.Expr{} mut node := ast.Expr{}
node = sel_expr node = sel_expr
if is_filter { if is_filter {
p.close_scope() p.close_scope()
@ -798,7 +798,7 @@ fn (var p Parser) dot_expr(left ast.Expr) ast.Expr {
// `.green` // `.green`
// `pref.BuildMode.default_mode` // `pref.BuildMode.default_mode`
fn (var p Parser) enum_val() ast.EnumVal { fn (mut p Parser) enum_val() ast.EnumVal {
p.check(.dot) p.check(.dot)
val := p.check_name() val := p.check_name()
return ast.EnumVal{ return ast.EnumVal{
@ -807,13 +807,13 @@ fn (var p Parser) enum_val() ast.EnumVal {
} }
} }
fn (var p Parser) string_expr() ast.Expr { fn (mut p Parser) string_expr() ast.Expr {
is_raw := p.tok.kind == .name && p.tok.lit == 'r' is_raw := p.tok.kind == .name && p.tok.lit == 'r'
is_cstr := p.tok.kind == .name && p.tok.lit == 'c' is_cstr := p.tok.kind == .name && p.tok.lit == 'c'
if is_raw || is_cstr { if is_raw || is_cstr {
p.next() p.next()
} }
var node := ast.Expr{} mut node := ast.Expr{}
val := p.tok.lit val := p.tok.lit
pos := p.tok.position() pos := p.tok.position()
if p.peek_tok.kind != .str_dollar { if p.peek_tok.kind != .str_dollar {
@ -826,9 +826,9 @@ fn (var p Parser) string_expr() ast.Expr {
} }
return node return node
} }
var exprs := []ast.Expr mut exprs := []ast.Expr
var vals := []string mut vals := []string
var efmts := []string mut efmts := []string
// Handle $ interpolation // Handle $ interpolation
for p.tok.kind == .string { for p.tok.kind == .string {
vals << p.tok.lit vals << p.tok.lit
@ -838,7 +838,7 @@ fn (var p Parser) string_expr() ast.Expr {
} }
p.check(.str_dollar) p.check(.str_dollar)
exprs << p.expr(0) exprs << p.expr(0)
var efmt := []string mut efmt := []string
if p.tok.kind == .colon { if p.tok.kind == .colon {
efmt << ':' efmt << ':'
p.next() p.next()
@ -868,10 +868,10 @@ fn (var p Parser) string_expr() ast.Expr {
return node return node
} }
fn (var p Parser) parse_number_literal() ast.Expr { fn (mut p Parser) parse_number_literal() ast.Expr {
lit := p.tok.lit lit := p.tok.lit
pos := p.tok.position() pos := p.tok.position()
var node := ast.Expr{} mut node := ast.Expr{}
if lit.index_any('.eE') >= 0 && lit[..2] !in ['0x', '0X', '0o', '0O', '0b', '0B'] { if lit.index_any('.eE') >= 0 && lit[..2] !in ['0x', '0X', '0o', '0O', '0b', '0B'] {
node = ast.FloatLiteral{ node = ast.FloatLiteral{
val: lit val: lit
@ -887,8 +887,8 @@ fn (var p Parser) parse_number_literal() ast.Expr {
return node return node
} }
fn (var p Parser) module_decl() ast.Module { fn (mut p Parser) module_decl() ast.Module {
var name := 'main' mut name := 'main'
is_skipped := p.tok.kind != .key_module is_skipped := p.tok.kind != .key_module
if !is_skipped { if !is_skipped {
p.check(.key_module) p.check(.key_module)
@ -903,10 +903,10 @@ fn (var p Parser) module_decl() ast.Module {
} }
} }
fn (var p Parser) parse_import() ast.Import { fn (mut p Parser) parse_import() ast.Import {
pos := p.tok.position() pos := p.tok.position()
var mod_name := p.check_name() mut mod_name := p.check_name()
var mod_alias := mod_name mut mod_alias := mod_name
for p.tok.kind == .dot { for p.tok.kind == .dot {
p.check(.dot) p.check(.dot)
submod_name := p.check_name() submod_name := p.check_name()
@ -926,9 +926,9 @@ fn (var p Parser) parse_import() ast.Import {
} }
} }
fn (var p Parser) import_stmt() []ast.Import { fn (mut p Parser) import_stmt() []ast.Import {
p.check(.key_import) p.check(.key_import)
var imports := []ast.Import mut imports := []ast.Import
if p.tok.kind == .lpar { if p.tok.kind == .lpar {
p.check(.lpar) p.check(.lpar)
for p.tok.kind != .rpar { for p.tok.kind != .rpar {
@ -945,7 +945,7 @@ fn (var p Parser) import_stmt() []ast.Import {
return imports return imports
} }
fn (var p Parser) const_decl() ast.ConstDecl { fn (mut p Parser) const_decl() ast.ConstDecl {
start_pos := p.tok.position() start_pos := p.tok.position()
is_pub := p.tok.kind == .key_pub is_pub := p.tok.kind == .key_pub
if is_pub { if is_pub {
@ -957,7 +957,7 @@ fn (var p Parser) const_decl() ast.ConstDecl {
p.error('consts must be grouped, e.g.\nconst (\n\ta = 1\n)') p.error('consts must be grouped, e.g.\nconst (\n\ta = 1\n)')
} }
p.next() // ( p.next() // (
var fields := []ast.ConstField mut fields := []ast.ConstField
for p.tok.kind != .rpar { for p.tok.kind != .rpar {
if p.tok.kind == .comment { if p.tok.kind == .comment {
p.comment() p.comment()
@ -983,11 +983,11 @@ fn (var p Parser) const_decl() ast.ConstDecl {
} }
} }
fn (var p Parser) return_stmt() ast.Return { fn (mut p Parser) return_stmt() ast.Return {
first_pos := p.tok.position() first_pos := p.tok.position()
p.next() p.next()
// return expressions // return expressions
var exprs := []ast.Expr mut exprs := []ast.Expr
if p.tok.kind == .rcbr { if p.tok.kind == .rcbr {
return ast.Return{ return ast.Return{
pos: first_pos pos: first_pos
@ -1010,7 +1010,7 @@ fn (var p Parser) return_stmt() ast.Return {
} }
// left hand side of `=` or `:=` in `a,b,c := 1,2,3` // left hand side of `=` or `:=` in `a,b,c := 1,2,3`
fn (var p Parser) global_decl() ast.GlobalDecl { fn (mut p Parser) global_decl() ast.GlobalDecl {
if !p.pref.translated && !p.pref.is_live && !p.builtin_mod && !p.pref.building_v && p.mod != if !p.pref.translated && !p.pref.is_live && !p.builtin_mod && !p.pref.building_v && p.mod !=
'ui' && p.mod != 'gg2' && p.mod != 'uiold' && !os.getwd().contains('/volt') && !p.pref.enable_globals { 'ui' && p.mod != 'gg2' && p.mod != 'uiold' && !os.getwd().contains('/volt') && !p.pref.enable_globals {
p.error('use `v --enable-globals ...` to enable globals') p.error('use `v --enable-globals ...` to enable globals')
@ -1019,7 +1019,7 @@ fn (var p Parser) global_decl() ast.GlobalDecl {
name := p.check_name() name := p.check_name()
// println(name) // println(name)
typ := p.parse_type() typ := p.parse_type()
var expr := ast.Expr{} mut expr := ast.Expr{}
has_expr := p.tok.kind == .assign has_expr := p.tok.kind == .assign
if has_expr { if has_expr {
p.next() p.next()
@ -1050,7 +1050,7 @@ fn (var p Parser) global_decl() ast.GlobalDecl {
return glob return glob
} }
fn (var p Parser) enum_decl() ast.EnumDecl { fn (mut p Parser) enum_decl() ast.EnumDecl {
is_pub := p.tok.kind == .key_pub is_pub := p.tok.kind == .key_pub
start_pos := p.tok.position() start_pos := p.tok.position()
if is_pub { if is_pub {
@ -1060,15 +1060,15 @@ fn (var p Parser) enum_decl() ast.EnumDecl {
end_pos := p.tok.position() end_pos := p.tok.position()
name := p.prepend_mod(p.check_name()) name := p.prepend_mod(p.check_name())
p.check(.lcbr) p.check(.lcbr)
var vals := []string mut vals := []string
// mut default_exprs := []ast.Expr // mut default_exprs := []ast.Expr
var fields := []ast.EnumField mut fields := []ast.EnumField
for p.tok.kind != .eof && p.tok.kind != .rcbr { for p.tok.kind != .eof && p.tok.kind != .rcbr {
pos := p.tok.position() pos := p.tok.position()
val := p.check_name() val := p.check_name()
vals << val vals << val
var expr := ast.Expr{} mut expr := ast.Expr{}
var has_expr := false mut has_expr := false
// p.warn('enum val $val') // p.warn('enum val $val')
if p.tok.kind == .assign { if p.tok.kind == .assign {
p.next() p.next()
@ -1105,7 +1105,7 @@ fn (var p Parser) enum_decl() ast.EnumDecl {
} }
} }
fn (var p Parser) type_decl() ast.TypeDecl { fn (mut p Parser) type_decl() ast.TypeDecl {
start_pos := p.tok.position() start_pos := p.tok.position()
is_pub := p.tok.kind == .key_pub is_pub := p.tok.kind == .key_pub
if is_pub { if is_pub {
@ -1115,7 +1115,7 @@ fn (var p Parser) type_decl() ast.TypeDecl {
end_pos := p.tok.position() end_pos := p.tok.position()
decl_pos := start_pos.extend(end_pos) decl_pos := start_pos.extend(end_pos)
name := p.check_name() name := p.check_name()
var sum_variants := []table.Type mut sum_variants := []table.Type
if p.tok.kind == .assign { if p.tok.kind == .assign {
p.next() // TODO require `=` p.next() // TODO require `=`
} }
@ -1176,7 +1176,7 @@ fn (var p Parser) type_decl() ast.TypeDecl {
} }
} }
fn (var p Parser) assoc() ast.Assoc { fn (mut p Parser) assoc() ast.Assoc {
var_name := p.check_name() var_name := p.check_name()
pos := p.tok.position() pos := p.tok.position()
v := p.scope.find_var(var_name) or { v := p.scope.find_var(var_name) or {
@ -1184,8 +1184,8 @@ fn (var p Parser) assoc() ast.Assoc {
return ast.Assoc{} return ast.Assoc{}
} }
// println('assoc var $name typ=$var.typ') // println('assoc var $name typ=$var.typ')
var fields := []string mut fields := []string
var vals := []ast.Expr mut vals := []ast.Expr
p.check(.pipe) p.check(.pipe)
for { for {
fields << p.check_name() fields << p.check_name()

View File

@ -7,10 +7,10 @@ import v.ast
import v.table import v.table
import v.token import v.token
pub fn (var p Parser) expr(precedence int) ast.Expr { pub fn (mut p Parser) expr(precedence int) ast.Expr {
// println('\n\nparser.expr()') // println('\n\nparser.expr()')
var typ := table.void_type mut typ := table.void_type
var node := ast.Expr{} mut node := ast.Expr{}
is_stmt_ident := p.is_stmt_ident is_stmt_ident := p.is_stmt_ident
p.is_stmt_ident = false p.is_stmt_ident = false
// Prefix // Prefix
@ -175,19 +175,19 @@ pub fn (var p Parser) expr(precedence int) ast.Expr {
return node return node
} }
fn (var p Parser) infix_expr(left ast.Expr) ast.Expr { fn (mut p Parser) infix_expr(left ast.Expr) ast.Expr {
op := p.tok.kind op := p.tok.kind
// mut typ := p. // mut typ := p.
// println('infix op=$op.str()') // println('infix op=$op.str()')
precedence := p.tok.precedence() precedence := p.tok.precedence()
pos := p.tok.position() pos := p.tok.position()
p.next() p.next()
var right := ast.Expr{} mut right := ast.Expr{}
if op == .key_is { if op == .key_is {
p.inside_is = true p.inside_is = true
} }
right = p.expr(precedence) right = p.expr(precedence)
var expr := ast.Expr{} mut expr := ast.Expr{}
expr = ast.InfixExpr{ expr = ast.InfixExpr{
left: left left: left
right: right right: right
@ -197,7 +197,7 @@ fn (var p Parser) infix_expr(left ast.Expr) ast.Expr {
return expr return expr
} }
fn (var p Parser) prefix_expr() ast.PrefixExpr { fn (mut p Parser) prefix_expr() ast.PrefixExpr {
pos := p.tok.position() pos := p.tok.position()
op := p.tok.kind op := p.tok.kind
if op == .amp { if op == .amp {