From af224b4933086860bf078dd59885290d4674a5a1 Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Thu, 16 Apr 2020 15:32:11 +0200 Subject: [PATCH] parser/cgen: is keyword --- vlib/v/checker/checker.v | 6 ++++++ vlib/v/gen/cgen.v | 23 ++++++++++++++--------- vlib/v/parser/parser.v | 18 ++++++++++++++---- vlib/v/tests/mut_test.v | 13 +++++++------ vlib/v/tests/sum_type_test.v | 31 +++++++++++++++++++++++++++++++ vlib/v/token/token.v | 6 ++++-- 6 files changed, 76 insertions(+), 21 deletions(-) create mode 100644 vlib/v/tests/sum_type_test.v diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 1366b4b7b1..3907251c0c 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -196,6 +196,9 @@ pub fn (c mut Checker) infix_expr(infix_expr mut ast.InfixExpr) table.Type { left_type := c.expr(infix_expr.left) infix_expr.left_type = left_type c.expected_type = left_type + if infix_expr.op == .key_is { + return table.bool_type + } right_type := c.expr(infix_expr.right) infix_expr.right_type = right_type right := c.table.get_type_symbol(right_type) @@ -1709,6 +1712,9 @@ pub fn (c mut Checker) warn(s string, pos token.Position) { } pub fn (c mut Checker) error(message string, pos token.Position) { + if c.pref.is_verbose { + print_backtrace() + } c.warn_or_error(message, pos, false) } diff --git a/vlib/v/gen/cgen.v b/vlib/v/gen/cgen.v index d8b3519606..1638d77465 100644 --- a/vlib/v/gen/cgen.v +++ b/vlib/v/gen/cgen.v @@ -126,15 +126,10 @@ pub fn cgen(files []ast.File, table &table.Table, pref &pref.Preferences) string } // g.finish() - return g.hashes() + - '\n// V typedefs:\n' + g.typedefs.str() + - '\n// V typedefs2:\n' + g.typedefs2.str() + - '\n// V cheaders:\n' + g.cheaders.str() + - '\n// V includes:\n' + g.includes.str() + - '\n// V definitions:\n' + g.definitions.str() + - '\n// V gowrappers:\n' + g.gowrappers.str() + - '\n// V stringliterals:\n' + g.stringliterals.str() + - '\n// V out\n' + g.out.str() + return g.hashes() + '\n// V typedefs:\n' + g.typedefs.str() + '\n// V typedefs2:\n' + g.typedefs2.str() + + '\n// V cheaders:\n' + g.cheaders.str() + '\n// V includes:\n' + g.includes.str() + '\n// V definitions:\n' + + g.definitions.str() + '\n// V gowrappers:\n' + g.gowrappers.str() + '\n// V stringliterals:\n' + + g.stringliterals.str() + '\n// V out\n' + g.out.str() } pub fn (g Gen) hashes() string { @@ -1211,6 +1206,10 @@ fn (g mut Gen) infix_expr(node ast.InfixExpr) { // string + string, string == string etc // g.infix_op = node.op left_sym := g.table.get_type_symbol(node.left_type) + if node.op == .key_is { + g.is_expr(node) + return + } right_sym := g.table.get_type_symbol(node.right_type) if node.left_type == table.string_type_idx && node.op != .key_in && node.op != .not_in { fn_name := match node.op { @@ -2828,6 +2827,12 @@ fn (g mut Gen) go_stmt(node ast.GoStmt) { } } +fn (g mut Gen) is_expr(node ast.InfixExpr) { + g.expr(node.left) + g.write('.typ == ') + g.expr(node.right) +} + // already generated styp, reuse it fn (g mut Gen) gen_str_for_type(sym table.TypeSymbol, styp string) { if sym.has_method('str') || styp in g.str_types { diff --git a/vlib/v/parser/parser.v b/vlib/v/parser/parser.v index 038803eed7..eff2c72b6e 100644 --- a/vlib/v/parser/parser.v +++ b/vlib/v/parser/parser.v @@ -21,7 +21,7 @@ mut: peek_tok token.Token table &table.Table is_c bool - is_js bool + is_js bool inside_if bool inside_for bool inside_fn bool @@ -39,6 +39,7 @@ mut: inside_match bool // to separate `match A { }` from `Struct{}` inside_match_case bool // to separate `match_expr { }` from `Struct{}` is_stmt_ident bool // true while the beginning of a statement is an ident/selector + inside_is bool // `is Type`, expecting type } // for tests @@ -616,6 +617,11 @@ fn (p mut Parser) struct_init(short_syntax bool) ast.StructInit { pub fn (p mut Parser) name_expr() ast.Expr { var node := ast.Expr{} + if p.inside_is { + return ast.Type{ + typ: p.parse_type() + } + } is_c := p.tok.lit == 'C' is_js := p.tok.lit == 'JS' var mod := '' @@ -635,8 +641,8 @@ pub fn (p mut Parser) name_expr() ast.Expr { return p.string_expr() } known_var := p.scope.known_var(p.tok.lit) - if p.peek_tok.kind == .dot && !known_var && (is_c || is_js || p.known_import(p.tok.lit) || p.mod.all_after('.') == - p.tok.lit) { + if p.peek_tok.kind == .dot && !known_var && (is_c || is_js || p.known_import(p.tok.lit) || + p.mod.all_after('.') == p.tok.lit) { if is_c { mod = 'C' } else if is_js { @@ -1044,7 +1050,11 @@ fn (p mut Parser) infix_expr(left ast.Expr) ast.Expr { pos := p.tok.position() p.next() var right := ast.Expr{} + if op == .key_is { + p.inside_is = true + } right = p.expr(precedence) + p.inside_is = false var expr := ast.Expr{} expr = ast.InfixExpr{ left: left @@ -1511,7 +1521,7 @@ fn (p mut Parser) const_decl() ast.ConstDecl { if p.tok.kind != .lpar { p.error('consts must be grouped, e.g.\nconst (\n\ta = 1\n)') } - p.next() // ( + p.next() // ( var fields := []ast.ConstField for p.tok.kind != .rpar { if p.tok.kind == .comment { diff --git a/vlib/v/tests/mut_test.v b/vlib/v/tests/mut_test.v index 2aa760b2f5..e09adb3467 100644 --- a/vlib/v/tests/mut_test.v +++ b/vlib/v/tests/mut_test.v @@ -14,7 +14,7 @@ fn foo(b int, a mut []int) { } fn test_mut() { - mut numbers := [1, 2, 3] + var numbers := [1, 2, 3] foo(7, mut numbers) assert numbers.len == 3 // TODO bring back once << works with mutable args @@ -23,15 +23,16 @@ fn test_mut() { // assert numbers[3] == 4 println(numbers) n := 1 - mut b := &n - *b = 10 - //mut b := mut a - //b = 10 + var b := &n + // + (*b) = 10 + // mut b := mut a + // b = 10 } fn test_mut_2() { zero := 0 - mut b := B{} + var b := B{} b.a << A{} b.a[0].v = [9, 8, 7] b.a[0].v << 6 diff --git a/vlib/v/tests/sum_type_test.v b/vlib/v/tests/sum_type_test.v new file mode 100644 index 0000000000..8d22581b53 --- /dev/null +++ b/vlib/v/tests/sum_type_test.v @@ -0,0 +1,31 @@ +type Expr = IfExpr | IntegerLiteral + +struct IfExpr { + pos int +} + +struct IntegerLiteral { + val string +} + +fn handle(e Expr) string { + assert e is IntegerLiteral + if e is IntegerLiteral { + println('int') + } + match e { + IntegerLiteral { + return 'int' + } + IfExpr { + return 'if' + } + } + return '' +} + +fn test_expr() { + expr := IntegerLiteral{'12'} + assert handle(expr) == 'int' + // assert expr is IntegerLiteral +} diff --git a/vlib/v/token/token.v b/vlib/v/token/token.v index a988a323e0..d49831a366 100644 --- a/vlib/v/token/token.v +++ b/vlib/v/token/token.v @@ -101,6 +101,7 @@ pub enum Kind { key_import_const key_in key_interface + key_is // key_it key_match key_module @@ -246,6 +247,7 @@ fn build_token_str() []string { s[Kind.key_select] = 'select' s[Kind.key_none] = 'none' s[Kind.key_offsetof] = '__offsetof' + s[Kind.key_is] = 'is' s[Kind.key_var] = 'var' return s } @@ -385,7 +387,7 @@ pub fn (tok Token) precedence() int { .left_shift_assign, .right_shift_assign, .mult_assign, .xor_assign { return int(Precedence.assign) } - .key_in, .not_in, .key_as { + .key_in, .not_in, .key_as, .key_is { return int(Precedence.in_as) } .logical_or, .and { @@ -425,7 +427,7 @@ pub fn (k Kind) is_start_of_type() bool { pub fn (kind Kind) is_infix() bool { return kind in [.plus, .minus, .mod, .mul, .div, .eq, .ne, .gt, .lt, .key_in, // - .key_as, .ge, .le, .logical_or, .xor, .not_in, + .key_as, .ge, .le, .logical_or, .xor, .not_in, .key_is, // .and, .dot, .pipe, .amp, .left_shift, .right_shift] }