checker: check array and fields mutability
parent
ce1215f507
commit
682838a0cf
|
@ -24,8 +24,8 @@ const (
|
|||
'vlib/v/tests/live_test.v', // Linux & Solaris only; since live does not actually work for now with v2, just skip
|
||||
'vlib/v/tests/asm_test.v', // skip everywhere for now, works on linux with cc != tcc
|
||||
]
|
||||
skip_on_linux = []string
|
||||
skip_on_non_linux = []string
|
||||
skip_on_linux = []string{}
|
||||
skip_on_non_linux = []string{}
|
||||
)
|
||||
|
||||
fn main() {
|
||||
|
|
|
@ -141,7 +141,7 @@ fn test_bf_from_str() {
|
|||
rand.seed(time.now().unix)
|
||||
len := 80
|
||||
mut input := ''
|
||||
for i in 0..len {
|
||||
for _ in 0..len {
|
||||
if rand.next(2) == 1 {
|
||||
input = input + '1'
|
||||
}
|
||||
|
@ -244,7 +244,7 @@ fn test_bf_resize() {
|
|||
rand.seed(time.now().unix)
|
||||
len := 80
|
||||
mut input := bitfield.new(rand.next(len) + 1)
|
||||
for i in 0..100 {
|
||||
for _ in 0..100 {
|
||||
input.resize(rand.next(len) + 1)
|
||||
input.setbit(input.getsize() - 1)
|
||||
}
|
||||
|
|
|
@ -7,11 +7,12 @@ import strings
|
|||
|
||||
pub struct array {
|
||||
pub:
|
||||
element_size int
|
||||
pub mut:
|
||||
data voidptr// Using a void pointer allows to implement arrays without generics and without generating
|
||||
// extra code for every type.
|
||||
len int
|
||||
cap int
|
||||
element_size int
|
||||
}
|
||||
|
||||
// Internal function, used by V (`nums := []int`)
|
||||
|
|
|
@ -33,6 +33,7 @@ pub mut:
|
|||
}
|
||||
|
||||
pub struct Line64 {
|
||||
pub mut:
|
||||
f_size_of_struct u32
|
||||
f_key voidptr
|
||||
f_line_number u32
|
||||
|
|
|
@ -5,6 +5,7 @@ struct User {
|
|||
}
|
||||
|
||||
struct A {
|
||||
mut:
|
||||
m map[string]int
|
||||
users map[string]User
|
||||
}
|
||||
|
@ -24,7 +25,7 @@ fn test_map() {
|
|||
assert 'hi' in m
|
||||
mut sum := 0
|
||||
// Test `for in`
|
||||
for key, val in m {
|
||||
for _, val in m {
|
||||
sum += val
|
||||
}
|
||||
assert sum == 80 + 101
|
||||
|
|
|
@ -51,7 +51,7 @@ pub:
|
|||
// hash_cache int
|
||||
|
||||
pub struct ustring {
|
||||
pub:
|
||||
pub mut:
|
||||
s string
|
||||
runes []int
|
||||
len int
|
||||
|
|
|
@ -435,7 +435,7 @@ pub fn (fs FlagParser) usage() string {
|
|||
if fs.flags.len > 0 {
|
||||
use += 'Options:\n'
|
||||
for f in fs.flags {
|
||||
mut onames:=[]string
|
||||
mut onames := []string{}
|
||||
if f.abbr != 0 {
|
||||
onames << '-${f.abbr.str()}'
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ fn test_rand_r_seed_update() {
|
|||
|
||||
for _ in 0..rnd_count {
|
||||
prev_seed := seed
|
||||
res := rand.rand_r(&seed)
|
||||
_ := rand.rand_r(&seed)
|
||||
|
||||
assert prev_seed != seed
|
||||
}
|
||||
|
|
|
@ -4,8 +4,9 @@
|
|||
module time
|
||||
|
||||
pub struct StopWatch {
|
||||
mut:
|
||||
pause_time u64
|
||||
pub:
|
||||
pub mut:
|
||||
start u64
|
||||
end u64
|
||||
}
|
||||
|
|
|
@ -134,9 +134,10 @@ mut:
|
|||
|
||||
pub struct ConstDecl {
|
||||
pub:
|
||||
fields []ConstField
|
||||
is_pub bool
|
||||
pos token.Position
|
||||
pub mut:
|
||||
fields []ConstField
|
||||
}
|
||||
|
||||
pub struct StructDecl {
|
||||
|
@ -162,10 +163,10 @@ pub:
|
|||
|
||||
pub struct StructInitField {
|
||||
pub:
|
||||
name string
|
||||
expr Expr
|
||||
pos token.Position
|
||||
mut:
|
||||
name string
|
||||
typ table.Type
|
||||
expected_type table.Type
|
||||
}
|
||||
|
@ -173,10 +174,10 @@ mut:
|
|||
pub struct StructInit {
|
||||
pub:
|
||||
pos token.Position
|
||||
fields []StructInitField
|
||||
is_short bool
|
||||
mut:
|
||||
typ table.Type
|
||||
fields []StructInitField
|
||||
}
|
||||
|
||||
// import statement
|
||||
|
@ -198,7 +199,6 @@ pub struct FnDecl {
|
|||
pub:
|
||||
name string
|
||||
stmts []Stmt
|
||||
return_type table.Type
|
||||
args []table.Arg
|
||||
is_deprecated bool
|
||||
is_pub bool
|
||||
|
@ -213,6 +213,8 @@ pub:
|
|||
is_builtin bool // this function is defined in builtin/strconv
|
||||
ctdefine string // has [if myflag] tag
|
||||
pos token.Position
|
||||
pub mut:
|
||||
return_type table.Type
|
||||
}
|
||||
|
||||
pub struct BranchStmt {
|
||||
|
@ -224,10 +226,10 @@ pub struct CallExpr {
|
|||
pub:
|
||||
pos token.Position
|
||||
left Expr // `user` in `user.register()`
|
||||
is_method bool
|
||||
mod string
|
||||
mut:
|
||||
name string
|
||||
is_method bool
|
||||
args []CallArg
|
||||
expected_arg_types []table.Type
|
||||
is_c bool
|
||||
|
@ -292,10 +294,11 @@ pub struct File {
|
|||
pub:
|
||||
path string
|
||||
mod Module
|
||||
imports []Import
|
||||
stmts []Stmt
|
||||
scope &Scope
|
||||
global_scope &Scope
|
||||
mut:
|
||||
imports []Import
|
||||
}
|
||||
|
||||
pub struct IdentFn {
|
||||
|
@ -331,11 +334,11 @@ pub:
|
|||
tok_kind token.Kind
|
||||
mod string
|
||||
pos token.Position
|
||||
is_mut bool
|
||||
mut:
|
||||
name string
|
||||
kind IdentKind
|
||||
info IdentInfo
|
||||
is_mut bool
|
||||
}
|
||||
|
||||
pub fn (i &Ident) var_info() IdentVar {
|
||||
|
@ -508,11 +511,11 @@ pub:
|
|||
|
||||
pub struct AssignStmt {
|
||||
pub:
|
||||
left []Ident
|
||||
right []Expr
|
||||
op token.Kind
|
||||
pos token.Position
|
||||
mut:
|
||||
pub mut:
|
||||
left []Ident
|
||||
left_types []table.Type
|
||||
right_types []table.Type
|
||||
is_static bool // for translated code only
|
||||
|
@ -670,8 +673,8 @@ pub:
|
|||
expr Expr // `buf`
|
||||
arg Expr // `n` in `string(buf, n)`
|
||||
typ table.Type // `string`
|
||||
typname string
|
||||
mut:
|
||||
typname string
|
||||
expr_type table.Type // `byteptr`
|
||||
has_arg bool
|
||||
}
|
||||
|
|
|
@ -121,7 +121,7 @@ pub fn (x Expr) str() string {
|
|||
return '${it.expr.str()}.${it.field}'
|
||||
}
|
||||
StringInterLiteral {
|
||||
res := []string{}
|
||||
mut res := []string{}
|
||||
res << "'"
|
||||
for i, val in it.vals {
|
||||
res << val
|
||||
|
|
|
@ -17,12 +17,12 @@ import v.depgraph
|
|||
|
||||
pub struct Builder {
|
||||
pub:
|
||||
pref &pref.Preferences
|
||||
table &table.Table
|
||||
checker checker.Checker
|
||||
compiled_dir string // contains os.real_path() of the dir of the final file beeing compiled, or the dir itself when doing `v .`
|
||||
module_path string
|
||||
mut:
|
||||
pref &pref.Preferences
|
||||
module_search_paths []string
|
||||
parsed_files []ast.File
|
||||
global_scope &ast.Scope
|
||||
|
|
|
@ -364,11 +364,7 @@ pub fn (mut c Checker) infix_expr(infix_expr mut ast.InfixExpr) table.Type {
|
|||
.left_shift {
|
||||
if left.kind == .array {
|
||||
// `array << elm`
|
||||
match infix_expr.left {
|
||||
ast.Ident {}
|
||||
ast.SelectorExpr {}
|
||||
else { println('typeof: ${typeof(infix_expr.left)}') }
|
||||
}
|
||||
c.fail_if_immutable(infix_expr.left)
|
||||
// the expressions have different types (array_x and x)
|
||||
if c.table.check(c.table.value_type(left_type), right_type) {
|
||||
// []T << T
|
||||
|
@ -446,6 +442,58 @@ pub fn (mut c Checker) infix_expr(infix_expr mut ast.InfixExpr) table.Type {
|
|||
}
|
||||
}
|
||||
|
||||
fn (mut c Checker) fail_if_immutable(expr ast.Expr) {
|
||||
match expr {
|
||||
ast.Ident {
|
||||
scope := c.file.scope.innermost(expr.position().pos)
|
||||
if v := scope.find_var(it.name) {
|
||||
if !v.is_mut && !v.typ.is_ptr() {
|
||||
c.error('`$it.name` is immutable, declare it with `mut` to make it mutable',
|
||||
it.pos)
|
||||
}
|
||||
}
|
||||
}
|
||||
ast.IndexExpr {
|
||||
c.fail_if_immutable(it.left)
|
||||
}
|
||||
ast.ParExpr {
|
||||
c.fail_if_immutable(it.expr)
|
||||
}
|
||||
ast.PrefixExpr {
|
||||
c.fail_if_immutable(it.right)
|
||||
}
|
||||
ast.SelectorExpr {
|
||||
// retrieve table.Field
|
||||
typ_sym := c.table.get_type_symbol(it.expr_type)
|
||||
match typ_sym.kind {
|
||||
.struct_ {
|
||||
struct_info := typ_sym.info as table.Struct
|
||||
field_info := struct_info.get_field(it.field)
|
||||
if !field_info.is_mut {
|
||||
type_str := c.table.type_to_str(it.expr_type)
|
||||
c.error('field `$it.field` of struct `${type_str}` is immutable', it.pos)
|
||||
}
|
||||
c.fail_if_immutable(it.expr)
|
||||
}
|
||||
.array, .string {
|
||||
// This should only happen in `builtin`
|
||||
// TODO Remove `crypto.rand` when possible (see vlib/crypto/rand/rand.v,
|
||||
// if `c_array_to_bytes_tmp` doesn't exist, then it's safe to remove it)
|
||||
if c.file.mod.name !in ['builtin', 'crypto.rand'] {
|
||||
c.error('`$typ_sym.kind` can not be modified', expr.position())
|
||||
}
|
||||
}
|
||||
else {
|
||||
c.error('unexpected symbol `${typ_sym.kind}`', expr.position())
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
c.error('unexpected expression `${typeof(expr)}`', expr.position())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn (mut c Checker) assign_expr(assign_expr mut ast.AssignExpr) {
|
||||
c.expected_type = table.void_type
|
||||
left_type := c.expr(assign_expr.left)
|
||||
|
@ -460,32 +508,7 @@ fn (mut c Checker) assign_expr(assign_expr mut ast.AssignExpr) {
|
|||
return
|
||||
}
|
||||
// Make sure the variable is mutable
|
||||
match assign_expr.left {
|
||||
ast.Ident {
|
||||
scope := c.file.scope.innermost(assign_expr.pos.pos)
|
||||
if v := scope.find_var(it.name) {
|
||||
if !v.is_mut {
|
||||
c.error('`$it.name` is immutable, declare it with `mut` to assign to it',
|
||||
assign_expr.pos)
|
||||
}
|
||||
}
|
||||
}
|
||||
ast.IndexExpr {
|
||||
// `m[key] = val`
|
||||
if it.left is ast.Ident {
|
||||
ident := it.left as ast.Ident
|
||||
// TODO copy pasta
|
||||
scope := c.file.scope.innermost(assign_expr.pos.pos)
|
||||
if v := scope.find_var(ident.name) {
|
||||
if !v.is_mut {
|
||||
c.error('`$ident.name` is immutable, declare it with `mut` to assign to it',
|
||||
assign_expr.pos)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {}
|
||||
}
|
||||
c.fail_if_immutable(assign_expr.left)
|
||||
// Single side check
|
||||
match assign_expr.op {
|
||||
.assign {} // No need to do single side check for =. But here put it first for speed.
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
vlib/v/checker/tests/immutable_array_field_assign.v:9:4: error: field `i` of struct `A` is immutable
|
||||
7| i: [0]
|
||||
8| }
|
||||
9| a.i[0] = 3
|
||||
^
|
||||
10| }
|
|
@ -0,0 +1,10 @@
|
|||
struct A {
|
||||
i []int
|
||||
}
|
||||
|
||||
fn main() {
|
||||
mut a := A{
|
||||
i: [0]
|
||||
}
|
||||
a.i[0] = 3
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
struct A {
|
||||
i []int
|
||||
}
|
||||
|
||||
fn main() {
|
||||
mut a := A{
|
||||
i: [0]
|
||||
}
|
||||
a.i[0] = 3
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
vlib/v/checker/tests/immutable_array_field_shift.v:14:4: error: field `a` of struct `B` is immutable
|
||||
12| a: A{}
|
||||
13| }
|
||||
14| b.a.i << 3
|
||||
^
|
||||
15| }
|
|
@ -0,0 +1,15 @@
|
|||
struct A {
|
||||
mut:
|
||||
i []int
|
||||
}
|
||||
|
||||
struct B {
|
||||
a A
|
||||
}
|
||||
|
||||
fn main() {
|
||||
mut b := B{
|
||||
a: A{}
|
||||
}
|
||||
b.a.i << 3
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
struct A {
|
||||
mut:
|
||||
i []int
|
||||
}
|
||||
|
||||
struct B {
|
||||
a A
|
||||
}
|
||||
|
||||
fn main() {
|
||||
mut b := B{
|
||||
a: A{}
|
||||
}
|
||||
b.a.i << 3
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
vlib/v/checker/tests/immutable_array_struct_assign.v:8:2: error: `a` is immutable, declare it with `mut` to make it mutable
|
||||
6| fn main() {
|
||||
7| a := A{}
|
||||
8| a.i[0] += 3
|
||||
^
|
||||
9| }
|
|
@ -0,0 +1,9 @@
|
|||
struct A {
|
||||
pub mut:
|
||||
i []int
|
||||
}
|
||||
|
||||
fn main() {
|
||||
a := A{}
|
||||
a.i[0] += 3
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
struct A {
|
||||
pub mut:
|
||||
i []int
|
||||
}
|
||||
|
||||
fn main() {
|
||||
a := A{}
|
||||
a.i[0] += 3
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
vlib/v/checker/tests/immutable_array_struct_shift.v:8:2: error: `a` is immutable, declare it with `mut` to make it mutable
|
||||
6| fn main() {
|
||||
7| a := []A{}
|
||||
8| a[0].i << 3
|
||||
^
|
||||
9| }
|
|
@ -0,0 +1,9 @@
|
|||
struct A {
|
||||
pub mut:
|
||||
i []int
|
||||
}
|
||||
|
||||
fn main() {
|
||||
a := []A{}
|
||||
a[0].i << 3
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
struct A {
|
||||
pub mut:
|
||||
i []int
|
||||
}
|
||||
|
||||
fn main() {
|
||||
a := []A{}
|
||||
a[0].i << 3
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
vlib/v/checker/tests/immutable_array_var.v:3:2: error: `a` is immutable, declare it with `mut` to make it mutable
|
||||
1| fn main() {
|
||||
2| a := [1, 2]
|
||||
3| a << 3
|
||||
^
|
||||
4| }
|
|
@ -0,0 +1,4 @@
|
|||
fn main() {
|
||||
a := [1, 2]
|
||||
a << 3
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
fn main() {
|
||||
a := [1, 2]
|
||||
a << 3
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
vlib/v/checker/tests/immutable_field.v:8:4: error: field `i1` of struct `A` is immutable
|
||||
6| fn main() {
|
||||
7| a := A{1}
|
||||
8| a.i1 = 2
|
||||
~~
|
||||
9| }
|
|
@ -0,0 +1,9 @@
|
|||
struct A {
|
||||
pub:
|
||||
i1 int
|
||||
}
|
||||
|
||||
fn main() {
|
||||
a := A{1}
|
||||
a.i1 = 2
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
struct A {
|
||||
pub:
|
||||
i1 int
|
||||
}
|
||||
|
||||
fn main() {
|
||||
a := A{1}
|
||||
a.i1 = 2
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
vlib/v/checker/tests/immutable_var.v:3:2: error: `a` is immutable, declare it with `mut` to make it mutable
|
||||
1| fn main() {
|
||||
2| a := 1
|
||||
3| a = 2
|
||||
^
|
||||
4| }
|
|
@ -0,0 +1,4 @@
|
|||
fn main() {
|
||||
a := 1
|
||||
a = 2
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
fn main() {
|
||||
a := 1
|
||||
a = 2
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
vlib/v/checker/tests/left_shift_err.v:3:7: error: cannot shift type string into array_int
|
||||
1| fn main() {
|
||||
2| l := []int{}
|
||||
2| mut l := []int{}
|
||||
3| l << 'test'
|
||||
~~~~~~
|
||||
4| }
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
fn main() {
|
||||
l := []int{}
|
||||
mut l := []int{}
|
||||
l << 'test'
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
fn main() {
|
||||
l := []int{}
|
||||
mut l := []int{}
|
||||
l << 'test'
|
||||
}
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
vlib/v/checker/tests/struct_pub_field.v:9:4: error: field `i` of struct `A` is immutable
|
||||
7| i: 1
|
||||
8| }
|
||||
9| a.i = 2
|
||||
^
|
||||
10| }
|
|
@ -0,0 +1,10 @@
|
|||
struct A {
|
||||
i int
|
||||
}
|
||||
|
||||
fn main() {
|
||||
a := A{
|
||||
i: 1
|
||||
}
|
||||
a.i = 2
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
struct A {
|
||||
i int
|
||||
}
|
||||
|
||||
fn main() {
|
||||
a := A{
|
||||
i: 1
|
||||
}
|
||||
a.i = 2
|
||||
}
|
|
@ -56,7 +56,6 @@ struct Gen {
|
|||
auto_str_funcs strings.Builder // function bodies of all auto generated _str funcs
|
||||
comptime_defines strings.Builder // custom defines, given by -d/-define flags on the CLI
|
||||
pcs_declarations strings.Builder // -prof profile counter declarations for each function
|
||||
pcs []ProfileCounterMeta // -prof profile counter fn_names => fn counter name
|
||||
table &table.Table
|
||||
pref &pref.Preferences
|
||||
mut:
|
||||
|
@ -86,6 +85,7 @@ mut:
|
|||
threaded_fns []string // for generating unique wrapper types and fns for `go xxx()`
|
||||
array_fn_definitions []string // array equality functions that have been defined
|
||||
is_json_fn bool // inside json.encode()
|
||||
pcs []ProfileCounterMeta // -prof profile counter fn_names => fn counter name
|
||||
}
|
||||
|
||||
const (
|
||||
|
|
|
@ -16,15 +16,15 @@ const (
|
|||
)
|
||||
|
||||
struct JsGen {
|
||||
out strings.Builder
|
||||
table &table.Table
|
||||
definitions strings.Builder
|
||||
pref &pref.Preferences
|
||||
mut:
|
||||
out strings.Builder
|
||||
namespaces map[string]strings.Builder
|
||||
namespaces_pub map[string][]string
|
||||
namespace string
|
||||
table &table.Table
|
||||
definitions strings.Builder
|
||||
pref &pref.Preferences
|
||||
namespace string
|
||||
doc &JsDoc
|
||||
mut:
|
||||
constants strings.Builder // all global V constants
|
||||
file ast.File
|
||||
tmp_count int
|
||||
|
@ -110,7 +110,7 @@ pub fn (g mut JsGen) escape_namespace() {
|
|||
|
||||
pub fn (g mut JsGen) push_pub_var(s string) {
|
||||
// Workaround until `m[key]<<val` works.
|
||||
arr := g.namespaces_pub[g.namespace]
|
||||
mut arr := g.namespaces_pub[g.namespace]
|
||||
arr << s
|
||||
g.namespaces_pub[g.namespace] = arr
|
||||
}
|
||||
|
@ -123,7 +123,7 @@ pub fn (g mut JsGen) find_class_methods(stmts []ast.Stmt) {
|
|||
// Found struct method, store it to be generated along with the class.
|
||||
class_name := g.table.get_type_symbol(it.receiver.typ).name
|
||||
// Workaround until `map[key] << val` works.
|
||||
arr := g.method_fn_decls[class_name]
|
||||
mut arr := g.method_fn_decls[class_name]
|
||||
arr << stmt
|
||||
g.method_fn_decls[class_name] = arr
|
||||
}
|
||||
|
|
|
@ -26,7 +26,6 @@ fn (mut g Gen) profile_fn(fn_name string, is_main bool){
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn (mut g Gen) gen_vprint_profile_stats() {
|
||||
g.pcs_declarations.writeln('void vprint_profile_stats(){')
|
||||
fstring := '"%14llu %14.3fms %14.0fns %s \\n"'
|
||||
|
|
|
@ -284,7 +284,7 @@ fn (mut p Parser) anon_fn() ast.AnonFn {
|
|||
stmts = p.parse_block_no_scope()
|
||||
}
|
||||
p.close_scope()
|
||||
func := table.Fn{
|
||||
mut func := table.Fn{
|
||||
args: args
|
||||
is_variadic: is_variadic
|
||||
return_type: return_type
|
||||
|
|
|
@ -109,21 +109,16 @@ fn (mut p Parser) match_expr() ast.MatchExpr {
|
|||
} else if p.tok.kind == .name && (p.tok.lit in table.builtin_type_names || (p.tok.lit[0].is_capital() &&
|
||||
!p.tok.lit.is_upper()) || p.peek_tok.kind == .dot) {
|
||||
// Sum type match
|
||||
// if sym.kind == .sum_type {
|
||||
// p.warn('is sum')
|
||||
// TODO `exprs << ast.Type{...}
|
||||
typ := p.parse_type()
|
||||
x := ast.Type{
|
||||
exprs << ast.Type{
|
||||
typ: typ
|
||||
}
|
||||
mut expr := ast.Expr{}
|
||||
expr = x
|
||||
exprs << expr
|
||||
p.scope.register('it', ast.Var{
|
||||
name: 'it'
|
||||
typ: typ.to_ptr()
|
||||
pos: cond_pos
|
||||
is_used: true
|
||||
is_mut: is_mut
|
||||
})
|
||||
// TODO
|
||||
if p.tok.kind == .comma {
|
||||
|
|
|
@ -565,7 +565,7 @@ pub fn (mut p Parser) parse_ident(is_c, is_js bool) ast.Ident {
|
|||
if p.expr_mod.len > 0 {
|
||||
name = '${p.expr_mod}.$name'
|
||||
}
|
||||
mut ident := ast.Ident{
|
||||
return ast.Ident{
|
||||
kind: .unresolved
|
||||
name: name
|
||||
is_c: is_c
|
||||
|
@ -573,7 +573,6 @@ pub fn (mut p Parser) parse_ident(is_c, is_js bool) ast.Ident {
|
|||
mod: p.mod
|
||||
pos: pos
|
||||
}
|
||||
return ident
|
||||
}
|
||||
|
||||
pub fn (mut p Parser) name_expr() ast.Expr {
|
||||
|
@ -694,9 +693,7 @@ pub fn (mut p Parser) name_expr() ast.Expr {
|
|||
mod: mod
|
||||
}
|
||||
} else {
|
||||
mut ident := ast.Ident{}
|
||||
ident = p.parse_ident(is_c, is_js)
|
||||
node = ident
|
||||
node = p.parse_ident(is_c, is_js)
|
||||
}
|
||||
p.expr_mod = ''
|
||||
return node
|
||||
|
|
|
@ -193,14 +193,12 @@ fn (mut p Parser) infix_expr(left ast.Expr) ast.Expr {
|
|||
p.inside_is = true
|
||||
}
|
||||
right = p.expr(precedence)
|
||||
mut expr := ast.Expr{}
|
||||
expr = ast.InfixExpr{
|
||||
return ast.InfixExpr{
|
||||
left: left
|
||||
right: right
|
||||
op: op
|
||||
pos: pos
|
||||
}
|
||||
return expr
|
||||
}
|
||||
|
||||
fn (mut p Parser) prefix_expr() ast.PrefixExpr {
|
||||
|
|
|
@ -38,6 +38,9 @@ fn (mut p Parser) struct_decl() ast.StructDecl {
|
|||
mut mut_pos := -1
|
||||
mut pub_pos := -1
|
||||
mut pub_mut_pos := -1
|
||||
mut is_field_mut := false
|
||||
mut is_field_pub := false
|
||||
mut is_field_global := false
|
||||
if !no_body {
|
||||
p.check(.lcbr)
|
||||
for p.tok.kind != .rcbr {
|
||||
|
@ -50,17 +53,29 @@ fn (mut p Parser) struct_decl() ast.StructDecl {
|
|||
if p.tok.kind == .key_mut {
|
||||
p.check(.key_mut)
|
||||
pub_mut_pos = fields.len
|
||||
is_field_pub = true
|
||||
is_field_mut = true
|
||||
is_field_global = false
|
||||
} else {
|
||||
pub_pos = fields.len
|
||||
is_field_pub = true
|
||||
is_field_mut = false
|
||||
is_field_global = false
|
||||
}
|
||||
p.check(.colon)
|
||||
} else if p.tok.kind == .key_mut {
|
||||
p.check(.key_mut)
|
||||
p.check(.colon)
|
||||
mut_pos = fields.len
|
||||
is_field_pub = false
|
||||
is_field_mut = true
|
||||
is_field_global = false
|
||||
} else if p.tok.kind == .key_global {
|
||||
p.check(.key_global)
|
||||
p.check(.colon)
|
||||
is_field_pub = true
|
||||
is_field_mut = true
|
||||
is_field_global = true
|
||||
}
|
||||
field_name := p.check_name()
|
||||
field_pos := p.tok.position()
|
||||
|
@ -108,6 +123,9 @@ fn (mut p Parser) struct_decl() ast.StructDecl {
|
|||
typ: typ
|
||||
default_expr: default_expr
|
||||
has_default_expr: has_default_expr
|
||||
is_pub: is_field_pub
|
||||
is_mut: is_field_mut
|
||||
is_global: is_field_global
|
||||
}
|
||||
// println('struct field $ti.name $field_name')
|
||||
}
|
||||
|
|
|
@ -311,6 +311,14 @@ pub fn (t &TypeSymbol) map_info() Map {
|
|||
}
|
||||
}
|
||||
|
||||
[inline]
|
||||
pub fn (t &TypeSymbol) struct_info() Struct {
|
||||
match t.info {
|
||||
Struct { return it }
|
||||
else { panic('TypeSymbol.struct_info(): no struct info for type: $t.name') }
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
pub fn (t TypeSymbol) str() string {
|
||||
return t.name
|
||||
|
@ -499,6 +507,7 @@ pub mut:
|
|||
}
|
||||
|
||||
pub struct Interface {
|
||||
mut:
|
||||
gen_types []string
|
||||
foo string
|
||||
}
|
||||
|
@ -522,6 +531,9 @@ mut:
|
|||
has_default_expr bool
|
||||
default_val string
|
||||
attr string
|
||||
is_pub bool
|
||||
is_mut bool
|
||||
is_global bool
|
||||
}
|
||||
|
||||
pub struct Array {
|
||||
|
@ -594,3 +606,19 @@ pub fn (table &Table) type_to_str(t Type) string {
|
|||
*/
|
||||
return res
|
||||
}
|
||||
|
||||
pub fn (s Struct) find_field(name string) ?Field {
|
||||
for field in s.fields {
|
||||
if field.name == name {
|
||||
return field
|
||||
}
|
||||
}
|
||||
return none
|
||||
}
|
||||
|
||||
pub fn (s Struct) get_field(name string) Field {
|
||||
if field := s.find_field(name) {
|
||||
return field
|
||||
}
|
||||
panic('unknown field `$name`')
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ import v.cflag
|
|||
|
||||
const (
|
||||
module_name = 'main'
|
||||
cdefines = []string
|
||||
cdefines = []string{}
|
||||
no_name = ''
|
||||
no_flag = ''
|
||||
no_os = ''
|
||||
|
|
|
@ -18,7 +18,6 @@ pub mut:
|
|||
|
||||
pub struct Fn {
|
||||
pub:
|
||||
name string
|
||||
args []Arg
|
||||
return_type Type
|
||||
is_variadic bool
|
||||
|
@ -28,6 +27,8 @@ pub:
|
|||
is_pub bool
|
||||
mod string
|
||||
ctdefine string // compile time define. myflag, when [if myflag] tag
|
||||
pub mut:
|
||||
name string
|
||||
}
|
||||
|
||||
pub struct Arg {
|
||||
|
@ -486,7 +487,7 @@ pub fn (t &Table) check(got, expected Type) bool {
|
|||
exp_type_sym := t.get_type_symbol(expected)
|
||||
//
|
||||
if exp_type_sym.kind == .interface_ {
|
||||
info := exp_type_sym.info as Interface
|
||||
mut info := exp_type_sym.info as Interface
|
||||
// println('gen_types before')
|
||||
// println(info.gen_types)
|
||||
info.gen_types << got_type_sym.name
|
||||
|
|
|
@ -40,5 +40,5 @@ pub fn cescaped_path(s string) string {
|
|||
}
|
||||
|
||||
pub fn is_fmt() bool {
|
||||
return os.executable().contains('vfmt')
|
||||
return os.executable().contains('vfmt')
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue