From b53fb365a6136d6be65aa86e324898dcd1744eb4 Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Fri, 17 Apr 2020 18:11:04 +0200 Subject: [PATCH] parser: move pratt logic to pratt.v --- vlib/v/parser/containers.v | 4 + vlib/v/parser/parser.v | 212 +---------------------------------- vlib/v/parser/pratt.v | 207 ++++++++++++++++++++++++++++++++++ vlib/v/tests/sum_type_test.v | 2 +- 4 files changed, 216 insertions(+), 209 deletions(-) create mode 100644 vlib/v/parser/containers.v create mode 100644 vlib/v/parser/pratt.v diff --git a/vlib/v/parser/containers.v b/vlib/v/parser/containers.v new file mode 100644 index 0000000000..27640a846f --- /dev/null +++ b/vlib/v/parser/containers.v @@ -0,0 +1,4 @@ +// 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 diff --git a/vlib/v/parser/parser.v b/vlib/v/parser/parser.v index 2feeeb4b2b..75f6f44761 100644 --- a/vlib/v/parser/parser.v +++ b/vlib/v/parser/parser.v @@ -685,188 +685,6 @@ pub fn (var p Parser) name_expr() ast.Expr { return node } -pub fn (var p Parser) expr(precedence int) ast.Expr { - // println('\n\nparser.expr()') - var typ := table.void_type - var node := ast.Expr{} - is_stmt_ident := p.is_stmt_ident - p.is_stmt_ident = false - // defer { - // if p.tok.kind == .comment { - // p.comment() - // } - // } - // Prefix - match p.tok.kind { - .name { - node = p.name_expr() - p.is_stmt_ident = is_stmt_ident - } - .string { - node = p.string_expr() - } - .dot { - // .enum_val - node = p.enum_val() - } - .chartoken { - node = ast.CharLiteral{ - val: p.tok.lit - } - p.next() - } - .minus, .amp, .mul, .not, .bit_not { - // -1, -a, !x, &x, ~x - node = p.prefix_expr() - } - .key_true, .key_false { - node = ast.BoolLiteral{ - val: p.tok.kind == .key_true - } - p.next() - } - .key_match { - node = p.match_expr() - } - .number { - node = p.parse_number_literal() - } - .lpar { - p.check(.lpar) - node = p.expr(0) - p.check(.rpar) - node = ast.ParExpr{ - expr: node - } - } - .key_if { - node = p.if_expr() - } - .lsbr { - node = p.array_init() - } - .key_none { - p.next() - node = ast.None{} - } - .key_sizeof { - p.next() // sizeof - p.check(.lpar) - if p.tok.lit == 'C' { - p.next() - p.check(.dot) - node = ast.SizeOf{ - type_name: p.check_name() - } - } else { - sizeof_type := p.parse_type() - node = ast.SizeOf{ - typ: sizeof_type - } - } - p.check(.rpar) - } - .key_typeof { - p.next() - p.check(.lpar) - expr := p.expr(0) - p.check(.rpar) - node = ast.TypeOf{ - expr: expr - } - } - .lcbr { - // Map `{"age": 20}` or `{ x | foo:bar, a:10 }` - p.next() - if p.tok.kind == .string { - node = p.map_init() - } else { - // it should be a struct - if p.peek_tok.kind == .pipe { - node = p.assoc() - } else if p.peek_tok.kind == .colon || p.tok.kind == .rcbr { - node = p.struct_init(true) // short_syntax: true - } else if p.tok.kind == .name { - p.next() - lit := if p.tok.lit != '' { p.tok.lit } else { p.tok.kind.str() } - p.error('unexpected ‘$lit‘, expecting ‘:‘') - } else { - p.error('unexpected ‘$p.tok.lit‘, expecting struct key') - } - } - p.check(.rcbr) - } - else { - if p.tok.kind == .comment { - println(p.tok.lit) - } - p.error('expr(): bad token `$p.tok.kind.str()`') - } - } - // Infix - for precedence < p.tok.precedence() { - if p.tok.kind.is_assign() { - node = p.assign_expr(node) - } else if p.tok.kind == .dot { - node = p.dot_expr(node) - p.is_stmt_ident = is_stmt_ident - } else if p.tok.kind == .lsbr { - node = p.index_expr(node) - } else if p.tok.kind == .key_as { - pos := p.tok.position() - p.next() - typ = p.parse_type() - node = ast.AsCast{ - expr: node - typ: typ - pos: pos - } - } else if p.tok.kind == .left_shift && p.is_stmt_ident { - // arr << elem - tok := p.tok - pos := tok.position() - p.next() - right := p.expr(precedence - 1) - node = ast.InfixExpr{ - left: node - right: right - op: tok.kind - pos: pos - } - } else if p.tok.kind.is_infix() { - node = p.infix_expr(node) - } else if p.tok.kind in [.inc, .dec] { - // Postfix - node = ast.PostfixExpr{ - op: p.tok.kind - expr: node - pos: p.tok.position() - } - p.next() - // return node // TODO bring back, only allow ++/-- in exprs in translated code - } else { - return node - } - } - return node -} - -fn (var p Parser) prefix_expr() ast.PrefixExpr { - pos := p.tok.position() - op := p.tok.kind - if op == .amp { - p.is_amp = true - } - p.next() - right := p.expr(token.Precedence.prefix) - p.is_amp = false - return ast.PrefixExpr{ - op: op - right: right - pos: pos - } -} - fn (var p Parser) index_expr(left ast.Expr) ast.IndexExpr { // left == `a` in `a[0]` p.next() // [ @@ -997,28 +815,6 @@ fn (var p Parser) dot_expr(left ast.Expr) ast.Expr { return node } -fn (var p Parser) infix_expr(left ast.Expr) ast.Expr { - op := p.tok.kind - // mut typ := p. - // println('infix op=$op.str()') - precedence := p.tok.precedence() - pos := p.tok.position() - p.next() - var right := ast.Expr{} - if op == .key_is { - p.inside_is = true - } - right = p.expr(precedence) - var expr := ast.Expr{} - expr = ast.InfixExpr{ - left: left - right: right - op: op - pos: pos - } - return expr -} - // `.green` // `pref.BuildMode.default_mode` fn (var p Parser) enum_val() ast.EnumVal { @@ -1777,10 +1573,10 @@ fn (var p Parser) enum_decl() ast.EnumDecl { has_expr = true } fields << ast.EnumField{ - : val - : pos - : expr - : has_expr + name: val + pos: pos + expr: expr + has_expr: has_expr } // Allow commas after enum, helpful for // enum Color { diff --git a/vlib/v/parser/pratt.v b/vlib/v/parser/pratt.v new file mode 100644 index 0000000000..401d9e3cf8 --- /dev/null +++ b/vlib/v/parser/pratt.v @@ -0,0 +1,207 @@ +// 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 + +pub fn (var p Parser) expr(precedence int) ast.Expr { + // println('\n\nparser.expr()') + var typ := table.void_type + var node := ast.Expr{} + is_stmt_ident := p.is_stmt_ident + p.is_stmt_ident = false + // Prefix + match p.tok.kind { + .name { + node = p.name_expr() + p.is_stmt_ident = is_stmt_ident + } + .string { + node = p.string_expr() + } + .dot { + // .enum_val + node = p.enum_val() + } + .chartoken { + node = ast.CharLiteral{ + val: p.tok.lit + } + p.next() + } + .minus, .amp, .mul, .not, .bit_not { + // -1, -a, !x, &x, ~x + node = p.prefix_expr() + } + .key_true, .key_false { + node = ast.BoolLiteral{ + val: p.tok.kind == .key_true + } + p.next() + } + .key_match { + node = p.match_expr() + } + .number { + node = p.parse_number_literal() + } + .lpar { + p.check(.lpar) + node = p.expr(0) + p.check(.rpar) + node = ast.ParExpr{ + expr: node + } + } + .key_if { + node = p.if_expr() + } + .lsbr { + node = p.array_init() + } + .key_none { + p.next() + node = ast.None{} + } + .key_sizeof { + p.next() // sizeof + p.check(.lpar) + if p.tok.lit == 'C' { + p.next() + p.check(.dot) + node = ast.SizeOf{ + type_name: p.check_name() + } + } else { + sizeof_type := p.parse_type() + node = ast.SizeOf{ + typ: sizeof_type + } + } + p.check(.rpar) + } + .key_typeof { + p.next() + p.check(.lpar) + expr := p.expr(0) + p.check(.rpar) + node = ast.TypeOf{ + expr: expr + } + } + .lcbr { + // Map `{"age": 20}` or `{ x | foo:bar, a:10 }` + p.next() + if p.tok.kind == .string { + node = p.map_init() + } else { + // it should be a struct + if p.peek_tok.kind == .pipe { + node = p.assoc() + } else if p.peek_tok.kind == .colon || p.tok.kind == .rcbr { + node = p.struct_init(true) // short_syntax: true + } else if p.tok.kind == .name { + p.next() + lit := if p.tok.lit != '' { p.tok.lit } else { p.tok.kind.str() } + p.error('unexpected ‘$lit‘, expecting ‘:‘') + } else { + p.error('unexpected ‘$p.tok.lit‘, expecting struct key') + } + } + p.check(.rcbr) + } + else { + if p.tok.kind == .comment { + println(p.tok.lit) + } + p.error('expr(): bad token `$p.tok.kind.str()`') + } + } + // Infix + for precedence < p.tok.precedence() { + if p.tok.kind.is_assign() { + node = p.assign_expr(node) + } else if p.tok.kind == .dot { + node = p.dot_expr(node) + p.is_stmt_ident = is_stmt_ident + } else if p.tok.kind == .lsbr { + node = p.index_expr(node) + } else if p.tok.kind == .key_as { + pos := p.tok.position() + p.next() + typ = p.parse_type() + node = ast.AsCast{ + expr: node + typ: typ + pos: pos + } + } else if p.tok.kind == .left_shift && p.is_stmt_ident { + // arr << elem + tok := p.tok + pos := tok.position() + p.next() + right := p.expr(precedence - 1) + node = ast.InfixExpr{ + left: node + right: right + op: tok.kind + pos: pos + } + } else if p.tok.kind.is_infix() { + node = p.infix_expr(node) + } else if p.tok.kind in [.inc, .dec] { + // Postfix + node = ast.PostfixExpr{ + op: p.tok.kind + expr: node + pos: p.tok.position() + } + p.next() + // return node // TODO bring back, only allow ++/-- in exprs in translated code + } else { + return node + } + } + return node +} + +fn (var p Parser) infix_expr(left ast.Expr) ast.Expr { + op := p.tok.kind + // mut typ := p. + // println('infix op=$op.str()') + precedence := p.tok.precedence() + pos := p.tok.position() + p.next() + var right := ast.Expr{} + if op == .key_is { + p.inside_is = true + } + right = p.expr(precedence) + var expr := ast.Expr{} + expr = ast.InfixExpr{ + left: left + right: right + op: op + pos: pos + } + return expr +} + +fn (var p Parser) prefix_expr() ast.PrefixExpr { + pos := p.tok.position() + op := p.tok.kind + if op == .amp { + p.is_amp = true + } + p.next() + right := p.expr(token.Precedence.prefix) + p.is_amp = false + return ast.PrefixExpr{ + op: op + right: right + pos: pos + } +} diff --git a/vlib/v/tests/sum_type_test.v b/vlib/v/tests/sum_type_test.v index ee0acca4b8..ade2a62eb7 100644 --- a/vlib/v/tests/sum_type_test.v +++ b/vlib/v/tests/sum_type_test.v @@ -16,7 +16,7 @@ fn handle(e Expr) string { match e { IntegerLiteral { assert it.val == '12' - assert e.val == '12' + // assert e.val == '12' return 'int' } IfExpr {