From 16931fd23f715cb56d90406ed96f267c162294c4 Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Fri, 17 Apr 2020 18:01:02 +0200 Subject: [PATCH] parser: move all struct logic to struct.v --- vlib/v/parser/parser.v | 253 +--------------------------------- vlib/v/parser/struct.v | 254 +++++++++++++++++++++++++++++++++++ vlib/v/tests/sum_type_test.v | 6 +- 3 files changed, 265 insertions(+), 248 deletions(-) create mode 100644 vlib/v/parser/struct.v diff --git a/vlib/v/parser/parser.v b/vlib/v/parser/parser.v index 271f039b63..2feeeb4b2b 100644 --- a/vlib/v/parser/parser.v +++ b/vlib/v/parser/parser.v @@ -569,69 +569,6 @@ pub fn (var p Parser) parse_ident(is_c, is_js bool) ast.Ident { return ident } -fn (var p Parser) struct_init(short_syntax bool) ast.StructInit { - first_pos := p.tok.position() - typ := if short_syntax { table.void_type } else { p.parse_type() } - p.expr_mod = '' - // sym := p.table.get_type_symbol(typ) - // p.warn('struct init typ=$sym.name') - if !short_syntax { - p.check(.lcbr) - } - var fields := []ast.StructInitField - var i := 0 - is_short_syntax := p.peek_tok.kind != .colon && p.tok.kind != .rcbr // `Vec{a,b,c} - // p.warn(is_short_syntax.str()) - for p.tok.kind != .rcbr { - p.check_comment() - var field_name := '' - if is_short_syntax { - expr := p.expr(0) - fields << ast.StructInitField{ - // name will be set later in checker - expr: expr - pos: expr.position() - } - } else { - first_field_pos := p.tok.position() - field_name = p.check_name() - p.check(.colon) - expr := p.expr(0) - last_field_pos := expr.position() - field_pos := token.Position{ - line_nr: first_field_pos.line_nr - pos: first_field_pos.pos - len: last_field_pos.pos - first_field_pos.pos + last_field_pos.len - } - fields << ast.StructInitField{ - name: field_name - expr: expr - pos: field_pos - } - } - i++ - if p.tok.kind == .comma { - p.check(.comma) - } - p.check_comment() - } - last_pos := p.tok.position() - if !short_syntax { - p.check(.rcbr) - } - node := ast.StructInit{ - typ: typ - fields: fields - pos: token.Position{ - line_nr: first_pos.line_nr - pos: first_pos.pos - len: last_pos.pos - first_pos.pos + last_pos.len - } - is_short: is_short_syntax - } - return node -} - pub fn (var p Parser) name_expr() ast.Expr { var node := ast.Expr{} if p.inside_is { @@ -1565,189 +1502,6 @@ fn (var p Parser) const_decl() ast.ConstDecl { } } -// structs and unions -fn (var p Parser) struct_decl() ast.StructDecl { - first_pos := p.tok.position() - is_pub := p.tok.kind == .key_pub - if is_pub { - p.next() - } - is_union := p.tok.kind == .key_union - if p.tok.kind == .key_struct { - p.check(.key_struct) - } else { - p.check(.key_union) - } - is_c := p.tok.lit == 'C' && p.peek_tok.kind == .dot - is_js := p.tok.lit == 'JS' && p.peek_tok.kind == .dot - if is_c { - p.next() // C || JS - p.next() // . - } - is_typedef := p.attr == 'typedef' - no_body := p.peek_tok.kind != .lcbr - if !is_c && !is_js && no_body { - p.error('`$p.tok.lit` lacks body') - } - var name := p.check_name() - // println('struct decl $name') - var ast_fields := []ast.StructField - var fields := []table.Field - var mut_pos := -1 - var pub_pos := -1 - var pub_mut_pos := -1 - var last_pos := token.Position{} - if !no_body { - p.check(.lcbr) - for p.tok.kind != .rcbr { - var comment := ast.Comment{} - if p.tok.kind == .comment { - comment = p.comment() - } - if p.tok.kind == .key_pub { - p.check(.key_pub) - if p.tok.kind == .key_mut { - p.check(.key_mut) - pub_mut_pos = fields.len - } else { - pub_pos = fields.len - } - p.check(.colon) - } else if p.tok.kind == .key_mut { - p.check(.key_mut) - p.check(.colon) - mut_pos = fields.len - } else if p.tok.kind == .key_global { - p.check(.key_global) - p.check(.colon) - } - field_name := p.check_name() - field_pos := p.tok.position() - // p.warn('field $field_name') - typ := p.parse_type() - /* - if name == '_net_module_s' { - s := p.table.get_type_symbol(typ) - println('XXXX' + s.str()) - } -*/ - var default_expr := ast.Expr{} - var has_default_expr := false - if p.tok.kind == .assign { - // Default value - p.next() - // default_expr = p.tok.lit - // p.expr(0) - default_expr = p.expr(0) - match default_expr { - ast.EnumVal { - it.typ = typ - } - // TODO: implement all types?? - else {} - } - has_default_expr = true - } - var attr := ast.Attr{} - if p.tok.kind == .lsbr { - attr = p.attribute() - } - if p.tok.kind == .comment { - comment = p.comment() - } - ast_fields << ast.StructField{ - name: field_name - pos: field_pos - typ: typ - comment: comment - default_expr: default_expr - has_default_expr: has_default_expr - attr: attr.name - } - fields << table.Field{ - name: field_name - typ: typ - default_expr: default_expr - has_default_expr: has_default_expr - } - // println('struct field $ti.name $field_name') - } - last_pos = p.tok.position() - p.check(.rcbr) - } - if is_c { - name = 'C.$name' - } else if is_js { - name = 'JS.$name' - } else { - name = p.prepend_mod(name) - } - t := table.TypeSymbol{ - kind: .struct_ - name: name - info: table.Struct{ - fields: fields - is_typedef: is_typedef - is_union: is_union - } - mod: p.mod - } - var ret := 0 - if p.builtin_mod && t.name in table.builtin_type_names { - // this allows overiding the builtins type - // with the real struct type info parsed from builtin - ret = p.table.register_builtin_type_symbol(t) - } else { - ret = p.table.register_type_symbol(t) - } - if ret == -1 { - p.error('cannot register type `$name`, another type with this name exists') - } - p.expr_mod = '' - pos := token.Position{ - line_nr: first_pos.line_nr - pos: first_pos.pos - len: last_pos.pos - first_pos.pos + last_pos.len - } - return ast.StructDecl{ - name: name - is_pub: is_pub - fields: ast_fields - pos: pos - mut_pos: mut_pos - pub_pos: pub_pos - pub_mut_pos: pub_mut_pos - is_c: is_c - is_js: is_js - is_union: is_union - } -} - -fn (var p Parser) interface_decl() ast.InterfaceDecl { - is_pub := p.tok.kind == .key_pub - if is_pub { - p.next() - } - p.next() // `interface` - interface_name := p.check_name() - p.check(.lcbr) - var field_names := []string - for p.tok.kind != .rcbr && p.tok.kind != .eof { - line_nr := p.tok.line_nr - name := p.check_name() - field_names << name - p.fn_args() - if p.tok.kind == .name && p.tok.line_nr == line_nr { - p.parse_type() - } - } - p.check(.rcbr) - return ast.InterfaceDecl{ - name: interface_name - field_names: field_names - } -} - fn (var p Parser) return_stmt() ast.Return { first_pos := p.tok.position() p.next() @@ -2022,7 +1776,12 @@ fn (var p Parser) enum_decl() ast.EnumDecl { expr = p.expr(0) has_expr = true } - fields << ast.EnumField{val, pos, expr, has_expr} + fields << ast.EnumField{ + : val + : pos + : expr + : has_expr + } // Allow commas after enum, helpful for // enum Color { // r,g,b diff --git a/vlib/v/parser/struct.v b/vlib/v/parser/struct.v new file mode 100644 index 0000000000..62f19a1126 --- /dev/null +++ b/vlib/v/parser/struct.v @@ -0,0 +1,254 @@ +// Copyright (c) 2019-2020 Alexander Medvednikov. All rights reserved. +// Use of this source code is governed by an MIT license +// that can be found in the LICENSE file. +module parser + +import v.ast +import v.table +import v.token + +fn (var p Parser) struct_decl() ast.StructDecl { + first_pos := p.tok.position() + is_pub := p.tok.kind == .key_pub + if is_pub { + p.next() + } + is_union := p.tok.kind == .key_union + if p.tok.kind == .key_struct { + p.check(.key_struct) + } else { + p.check(.key_union) + } + is_c := p.tok.lit == 'C' && p.peek_tok.kind == .dot + is_js := p.tok.lit == 'JS' && p.peek_tok.kind == .dot + if is_c { + p.next() // C || JS + p.next() // . + } + is_typedef := p.attr == 'typedef' + no_body := p.peek_tok.kind != .lcbr + if !is_c && !is_js && no_body { + p.error('`$p.tok.lit` lacks body') + } + var name := p.check_name() + // println('struct decl $name') + var ast_fields := []ast.StructField + var fields := []table.Field + var mut_pos := -1 + var pub_pos := -1 + var pub_mut_pos := -1 + var last_pos := token.Position{} + if !no_body { + p.check(.lcbr) + for p.tok.kind != .rcbr { + var comment := ast.Comment{} + if p.tok.kind == .comment { + comment = p.comment() + } + if p.tok.kind == .key_pub { + p.check(.key_pub) + if p.tok.kind == .key_mut { + p.check(.key_mut) + pub_mut_pos = fields.len + } else { + pub_pos = fields.len + } + p.check(.colon) + } else if p.tok.kind == .key_mut { + p.check(.key_mut) + p.check(.colon) + mut_pos = fields.len + } else if p.tok.kind == .key_global { + p.check(.key_global) + p.check(.colon) + } + field_name := p.check_name() + field_pos := p.tok.position() + // p.warn('field $field_name') + typ := p.parse_type() + /* + if name == '_net_module_s' { + s := p.table.get_type_symbol(typ) + println('XXXX' + s.str()) + } +*/ + var default_expr := ast.Expr{} + var has_default_expr := false + if p.tok.kind == .assign { + // Default value + p.next() + // default_expr = p.tok.lit + // p.expr(0) + default_expr = p.expr(0) + match default_expr { + ast.EnumVal { + it.typ = typ + } + // TODO: implement all types?? + else {} + } + has_default_expr = true + } + var attr := ast.Attr{} + if p.tok.kind == .lsbr { + attr = p.attribute() + } + if p.tok.kind == .comment { + comment = p.comment() + } + ast_fields << ast.StructField{ + name: field_name + pos: field_pos + typ: typ + comment: comment + default_expr: default_expr + has_default_expr: has_default_expr + attr: attr.name + } + fields << table.Field{ + name: field_name + typ: typ + default_expr: default_expr + has_default_expr: has_default_expr + } + // println('struct field $ti.name $field_name') + } + last_pos = p.tok.position() + p.check(.rcbr) + } + if is_c { + name = 'C.$name' + } else if is_js { + name = 'JS.$name' + } else { + name = p.prepend_mod(name) + } + t := table.TypeSymbol{ + kind: .struct_ + name: name + info: table.Struct{ + fields: fields + is_typedef: is_typedef + is_union: is_union + } + mod: p.mod + } + var ret := 0 + if p.builtin_mod && t.name in table.builtin_type_names { + // this allows overiding the builtins type + // with the real struct type info parsed from builtin + ret = p.table.register_builtin_type_symbol(t) + } else { + ret = p.table.register_type_symbol(t) + } + if ret == -1 { + p.error('cannot register type `$name`, another type with this name exists') + } + p.expr_mod = '' + pos := token.Position{ + line_nr: first_pos.line_nr + pos: first_pos.pos + len: last_pos.pos - first_pos.pos + last_pos.len + } + return ast.StructDecl{ + name: name + is_pub: is_pub + fields: ast_fields + pos: pos + mut_pos: mut_pos + pub_pos: pub_pos + pub_mut_pos: pub_mut_pos + is_c: is_c + is_js: is_js + is_union: is_union + } +} + +fn (var p Parser) struct_init(short_syntax bool) ast.StructInit { + first_pos := p.tok.position() + typ := if short_syntax { table.void_type } else { p.parse_type() } + p.expr_mod = '' + // sym := p.table.get_type_symbol(typ) + // p.warn('struct init typ=$sym.name') + if !short_syntax { + p.check(.lcbr) + } + var fields := []ast.StructInitField + var i := 0 + is_short_syntax := p.peek_tok.kind != .colon && p.tok.kind != .rcbr // `Vec{a,b,c} + // p.warn(is_short_syntax.str()) + for p.tok.kind != .rcbr { + p.check_comment() + var field_name := '' + if is_short_syntax { + expr := p.expr(0) + fields << ast.StructInitField{ + // name will be set later in checker + expr: expr + pos: expr.position() + } + } else { + first_field_pos := p.tok.position() + field_name = p.check_name() + p.check(.colon) + expr := p.expr(0) + last_field_pos := expr.position() + field_pos := token.Position{ + line_nr: first_field_pos.line_nr + pos: first_field_pos.pos + len: last_field_pos.pos - first_field_pos.pos + last_field_pos.len + } + fields << ast.StructInitField{ + name: field_name + expr: expr + pos: field_pos + } + } + i++ + if p.tok.kind == .comma { + p.check(.comma) + } + p.check_comment() + } + last_pos := p.tok.position() + if !short_syntax { + p.check(.rcbr) + } + node := ast.StructInit{ + typ: typ + fields: fields + pos: token.Position{ + line_nr: first_pos.line_nr + pos: first_pos.pos + len: last_pos.pos - first_pos.pos + last_pos.len + } + is_short: is_short_syntax + } + return node +} + +fn (var p Parser) interface_decl() ast.InterfaceDecl { + is_pub := p.tok.kind == .key_pub + if is_pub { + p.next() + } + p.next() // `interface` + interface_name := p.check_name() + p.check(.lcbr) + var field_names := []string + for p.tok.kind != .rcbr && p.tok.kind != .eof { + line_nr := p.tok.line_nr + name := p.check_name() + field_names << name + p.fn_args() + if p.tok.kind == .name && p.tok.line_nr == line_nr { + p.parse_type() + } + } + p.check(.rcbr) + return ast.InterfaceDecl{ + name: interface_name + field_names: field_names + } +} + diff --git a/vlib/v/tests/sum_type_test.v b/vlib/v/tests/sum_type_test.v index 8d22581b53..ee0acca4b8 100644 --- a/vlib/v/tests/sum_type_test.v +++ b/vlib/v/tests/sum_type_test.v @@ -15,6 +15,8 @@ fn handle(e Expr) string { } match e { IntegerLiteral { + assert it.val == '12' + assert e.val == '12' return 'int' } IfExpr { @@ -25,7 +27,9 @@ fn handle(e Expr) string { } fn test_expr() { - expr := IntegerLiteral{'12'} + expr := IntegerLiteral{ + val: '12' + } assert handle(expr) == 'int' // assert expr is IntegerLiteral }