parser: move pratt logic to pratt.v
parent
16931fd23f
commit
b53fb365a6
|
@ -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
|
|
@ -685,188 +685,6 @@ pub fn (var p Parser) name_expr() ast.Expr {
|
||||||
return node
|
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 {
|
fn (var p Parser) index_expr(left ast.Expr) ast.IndexExpr {
|
||||||
// left == `a` in `a[0]`
|
// left == `a` in `a[0]`
|
||||||
p.next() // [
|
p.next() // [
|
||||||
|
@ -997,28 +815,6 @@ fn (var p Parser) dot_expr(left ast.Expr) ast.Expr {
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
// `.green`
|
// `.green`
|
||||||
// `pref.BuildMode.default_mode`
|
// `pref.BuildMode.default_mode`
|
||||||
fn (var p Parser) enum_val() ast.EnumVal {
|
fn (var p Parser) enum_val() ast.EnumVal {
|
||||||
|
@ -1777,10 +1573,10 @@ fn (var p Parser) enum_decl() ast.EnumDecl {
|
||||||
has_expr = true
|
has_expr = true
|
||||||
}
|
}
|
||||||
fields << ast.EnumField{
|
fields << ast.EnumField{
|
||||||
: val
|
name: val
|
||||||
: pos
|
pos: pos
|
||||||
: expr
|
expr: expr
|
||||||
: has_expr
|
has_expr: has_expr
|
||||||
}
|
}
|
||||||
// Allow commas after enum, helpful for
|
// Allow commas after enum, helpful for
|
||||||
// enum Color {
|
// enum Color {
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
|
@ -16,7 +16,7 @@ fn handle(e Expr) string {
|
||||||
match e {
|
match e {
|
||||||
IntegerLiteral {
|
IntegerLiteral {
|
||||||
assert it.val == '12'
|
assert it.val == '12'
|
||||||
assert e.val == '12'
|
// assert e.val == '12'
|
||||||
return 'int'
|
return 'int'
|
||||||
}
|
}
|
||||||
IfExpr {
|
IfExpr {
|
||||||
|
|
Loading…
Reference in New Issue