parser: move pratt logic to pratt.v

pull/4465/head
Alexander Medvednikov 2020-04-17 18:11:04 +02:00
parent 16931fd23f
commit b53fb365a6
4 changed files with 216 additions and 209 deletions

View File

@ -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

View File

@ -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 {

View File

@ -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
}
}

View File

@ -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 {