1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

ast: return types, variable declaration

This commit is contained in:
Alexander Medvednikov 2019-12-26 13:27:35 +03:00
parent 320174bd5b
commit 0a3adb5de8
8 changed files with 187 additions and 48 deletions

View File

@ -4,8 +4,9 @@
module compiler module compiler
fn (p mut Parser) bool_expression() string { fn (p mut Parser) bool_expression() string {
is_ret := p.prev_tok == .key_return
start_ph := p.cgen.add_placeholder() start_ph := p.cgen.add_placeholder()
expected := p.expected_type mut expected := p.expected_type
tok := p.tok tok := p.tok
typ := p.bterm() typ := p.bterm()
mut got_and := false // to catch `a && b || c` in one expression without () mut got_and := false // to catch `a && b || c` in one expression without ()
@ -46,7 +47,11 @@ fn (p mut Parser) bool_expression() string {
println(tok.str()) println(tok.str())
p.error('expr() returns empty type') p.error('expr() returns empty type')
} }
if p.inside_return_expr { //is_ret { // return a,b hack TODO
expected = p.expected_type
}
if expected != typ && expected in p.table.sum_types { // TODO perf if expected != typ && expected in p.table.sum_types { // TODO perf
//p.warn('SUM CAST exp=$expected typ=$typ p.exp=$p.expected_type')
p.cgen.set_placeholder(start_ph, p.cgen.set_placeholder(start_ph,
//'/*SUM TYPE CAST*/($expected) { .obj = &($typ[]) { ') //'/*SUM TYPE CAST*/($expected) { .obj = &($typ[]) { ')
'/*SUM TYPE CAST*/($expected) { .obj = memdup(& ') '/*SUM TYPE CAST*/($expected) { .obj = memdup(& ')

View File

@ -272,8 +272,9 @@ fn (p &Parser) gen_fmt() {
s3 := s2.replace(') or{', ') or {') s3 := s2.replace(') or{', ') or {')
s4 := s3.replace(')or{', ') or {') s4 := s3.replace(')or{', ') or {')
s5 := s4.replace('or{', 'or {') s5 := s4.replace('or{', 'or {')
s6 := s5.replace('}}\n', '}\n\t}\n')
s := s5 s := s6
if s == '' { if s == '' {
return return

View File

@ -11,8 +11,9 @@ import (
struct Foo {} struct Foo {}
pub type Expr = Foo | IfExpr | BinaryExpr | UnaryExpr | pub type Expr = Foo | IfExpr | BinaryExpr | UnaryExpr |
StringLiteral | IntegerLiteral StringLiteral | IntegerLiteral | VarDecl
pub type Stmt = Foo | VarDecl
pub type Stmt = Foo | Foo //VarDecl
pub struct IntegerLiteral { pub struct IntegerLiteral {
pub: pub:
@ -43,6 +44,7 @@ pub struct VarDecl {
pub: pub:
name string name string
expr Expr expr Expr
typ Type
} }
@ -51,6 +53,18 @@ pub:
exprs []Expr exprs []Expr
} }
pub struct Type {
pub:
name string
}
pub const (
string_type = Type{'string'}
int_type = Type{'int'}
void_type = Type{'void'}
)
// A single identifier // A single identifier
struct Ident { struct Ident {
token token.Token token token.Token
@ -63,7 +77,9 @@ pub:
//op BinaryOp //op BinaryOp
op token.Token op token.Token
left Expr left Expr
left_type Type
right Expr right Expr
right_type Type
} }
pub struct UnaryExpr { pub struct UnaryExpr {
@ -90,13 +106,16 @@ struct ReturnStmt {
pub fn (x Expr) str() string { pub fn (x Expr) str() string {
match x { match x {
BinaryExpr { BinaryExpr {
return '(${it.left.str()}$it.op.str()${it.right.str()})' return '(${it.left.str()} $it.op.str() ${it.right.str()})'
} }
//ScalarExpr {
//return '${it.left.str()}$it.val'
//}
UnaryExpr { UnaryExpr {
return '${it.left.str()}$it.op.str()' return it.left.str() + it.op.str()
}
IntegerLiteral {
return it.val.str()
}
IntegerLiteral {
return '"$it.val"'
} }
else { return '' } else { return '' }
} }

View File

@ -41,12 +41,11 @@ const (
void_type = Type{'void'} void_type = Type{'void'}
) )
fn (g mut Gen) expr(node ast.Expr) Type { fn (g mut Gen) expr(node ast.Expr) {
//println('cgen expr()') //println('cgen expr()')
match node { match node {
ast.IntegerLiteral { ast.IntegerLiteral {
g.write(it.val.str()) g.write(it.val.str())
return int_type
} }
ast.UnaryExpr { ast.UnaryExpr {
g.expr(it.left) g.expr(it.left)
@ -54,10 +53,9 @@ fn (g mut Gen) expr(node ast.Expr) Type {
} }
ast.StringLiteral { ast.StringLiteral {
g.write('"$it.val"') g.write('"$it.val"')
return string_type
} }
ast.BinaryExpr { ast.BinaryExpr {
typ := g.expr(it.left) g.expr(it.left)
match it.op { match it.op {
.plus { g.write(' + ') } .plus { g.write(' + ') }
.minus { g.write(' - ') } .minus { g.write(' - ') }
@ -65,22 +63,24 @@ fn (g mut Gen) expr(node ast.Expr) Type {
.div { g.write(' / ') } .div { g.write(' / ') }
else {} else {}
} }
typ2 := g.expr(it.right) g.expr(it.right)
if typ.name != typ2.name { // if typ.name != typ2.name {
println('bad types $typ.name $typ2.name') //verror('bad types $typ.name $typ2.name')
} //}
return typ
} }
ast.VarDecl { ast.VarDecl {
g.write('var $it.name = ') g.write('$it.typ.name $it.name = ')
g.expr(it.expr) g.expr(it.expr)
g.writeln(';') g.writeln(';')
return void_type
} }
else { else {
println('bad node') println('bad node')
} }
} }
return void_type }
fn verror(s string) {
println(s)
exit(1)
} }

View File

@ -7,6 +7,7 @@ import (
compiler2.scanner compiler2.scanner
compiler2.ast compiler2.ast
compiler2.token compiler2.token
compiler2.table
) )
struct Parser { struct Parser {
@ -14,20 +15,49 @@ struct Parser {
mut: mut:
tok token.Token tok token.Token
lit string lit string
//vars []string
table &table.Table
} }
pub fn parse_expr(text string) ast.Expr { pub fn parse_expr(text string, table &table.Table) ast.Expr {
mut s := scanner.new_scanner(text) mut s := scanner.new_scanner(text)
res := s.scan() res := s.scan()
mut p := Parser{ mut p := Parser{
scanner: s scanner: s
tok: res.tok tok: res.tok
lit: res.lit lit: res.lit
table: table
} }
// return p.expr() expr,_ := p.expr(token.lowest_prec)
return p.expr(token.lowest_prec) return expr
} }
pub fn parse_file(text string, table &table.Table) ast.Program {
s := scanner.new_scanner(text)
mut exprs := []ast.Expr
mut p := Parser{
scanner: s
//tok: res.tok
//lit: res.lit
table: table
}
p.next()
for {
//res := s.scan()
if p.tok == .eof {
break
}
println('expr at ' + p.tok.str())
expr,_ := p.expr(token.lowest_prec)
exprs << expr
p.next()
}
println('nr exprs = $exprs.len')
println(exprs[0])
return ast.Program{exprs}
}
/*
pub fn parse_stmt(text string) ast.Stmt { pub fn parse_stmt(text string) ast.Stmt {
mut s := scanner.new_scanner(text) mut s := scanner.new_scanner(text)
res := s.scan() res := s.scan()
@ -38,6 +68,8 @@ pub fn parse_stmt(text string) ast.Stmt {
} }
return p.stmt() return p.stmt()
} }
*/
fn (p mut Parser) next() { fn (p mut Parser) next() {
res := p.scanner.scan() res := p.scanner.scan()
@ -47,15 +79,40 @@ fn (p mut Parser) next() {
} }
// Implementation of Pratt Precedence // Implementation of Pratt Precedence
pub fn (p mut Parser) expr(rbp int) ast.Expr { pub fn (p mut Parser) expr(rbp int) (ast.Expr,ast.Type) {
// null denotation (prefix) // null denotation (prefix)
tok := p.tok tok := p.tok
lit := p.lit lit := p.lit
p.next()
if p.tok == .name {
name := p.lit
p.next()
if p.tok == .decl_assign {
p.next()
mut node := ast.Expr{}
expr,t :=p.expr(token.lowest_prec)
if name in p.table.names {
verror('redefinition of `$name`')
}
p.table.names << name
println(p.table.names)
println('added $name')
// TODO can't return VarDecl{}
node = ast.VarDecl{
name: name
expr: expr//p.expr(token.lowest_prec)
typ: t
}//, ast.void_type
return node, ast.void_type
}
} else {
p.next()
}
mut node := ast.Expr{} mut node := ast.Expr{}
mut typ := ast.void_type
match tok { match tok {
.lpar { .lpar {
node = p.expr(0) node,typ = p.expr(0)
if p.tok != .rpar { if p.tok != .rpar {
panic('Parse Error: expected )') panic('Parse Error: expected )')
} }
@ -65,48 +122,70 @@ pub fn (p mut Parser) expr(rbp int) ast.Expr {
// TODO: fix bug. note odd conditon instead of else if (same below) // TODO: fix bug. note odd conditon instead of else if (same below)
if tok.is_scalar() { if tok.is_scalar() {
if tok == .str { if tok == .str {
node = ast.StringLiteral { node = ast.StringLiteral{
val: lit val: lit
} }
} if tok == .number { typ = ast.string_type
node = ast.IntegerLiteral { }
if tok == .number {
node = ast.IntegerLiteral{
val: lit.int() val: lit.int()
} }
typ = ast.int_type
} }
//else { // else {
//verror('bad scalar token') // verror('bad scalar token')
//} // }
} }
if !tok.is_scalar() && tok.is_unary() { if !tok.is_scalar() && tok.is_unary() {
expr,_ := p.expr(token.highest_prec)
node = ast.UnaryExpr{ node = ast.UnaryExpr{
left: p.expr(token.highest_prec) // left: p.expr(token.highest_prec)
left: expr
op: tok op: tok
} }
} }
}} }
}
// left binding power // left binding power
for rbp < p.tok.precedence() { for rbp < p.tok.precedence() {
tok2 := p.tok tok2 := p.tok
p.next() p.next()
//mut t1 := ast.Type{}
mut t2 := ast.Type{}
//mut q := false
// left denotation (infix) // left denotation (infix)
if tok2.is_right_assoc() { if tok2.is_right_assoc() {
//q = true
mut expr := ast.Expr{}
expr,t2 = p.expr(tok2.precedence() - 1)
node = ast.BinaryExpr{ node = ast.BinaryExpr{
left: node left: node
//left_type: t1
op: tok2 op: tok2
right: p.expr(tok2.precedence() - 1) // right: p.expr(tok2.precedence() - 1)
right: expr
}
if typ.name != t2.name {
println('bad types $typ.name $t2.name')
} }
} }
if !tok2.is_right_assoc() && tok2.is_left_assoc() { if !tok2.is_right_assoc() && tok2.is_left_assoc() {
mut expr := ast.Expr{}
expr,t2 = p.expr(tok2.precedence())
node = ast.BinaryExpr{ node = ast.BinaryExpr{
left: node left: node
op: tok2 op: tok2
right: p.expr(tok2.precedence()) right: expr
} }
} }
} }
return node return node,typ
} }
/*
fn (p mut Parser) stmt() ast.Stmt { fn (p mut Parser) stmt() ast.Stmt {
if p.tok == .name { if p.tok == .name {
name := p.lit name := p.lit
@ -131,6 +210,8 @@ fn (p mut Parser) stmt() ast.Stmt {
return ast.VarDecl{} return ast.VarDecl{}
} }
*/
fn verror(s string) { fn verror(s string) {
println(s) println(s)

View File

@ -3,6 +3,8 @@ module parser
import ( import (
compiler2.ast compiler2.ast
compiler2.cgen compiler2.cgen
compiler2.table
) )
fn test_parser() { fn test_parser() {
@ -11,8 +13,8 @@ fn test_parser() {
//expr := ast.BinaryExpr{} //expr := ast.BinaryExpr{}
// print using walk // print using walk
expr := parse_expr('3 + 7') //expr := parse_expr('3 + 7')
println('\n') //println('\n')
text_expr := [ text_expr := [
'1 += 2', '1 += 2',
@ -24,29 +26,53 @@ fn test_parser() {
'2 ^ 8 * (7 * 6)', '2 ^ 8 * (7 * 6)',
'20 + (10 * 15) / 5', // 50 '20 + (10 * 15) / 5', // 50
'(2) + (17*2-30) * (5)+2 - (8/2)*4', // 8 '(2) + (17*2-30) * (5)+2 - (8/2)*4', // 8
'2 + "hi"' '2 + "hi"',
'x := 10'
] ]
table := &table.Table{}
for s in text_expr { for s in text_expr {
// print using str method // print using str method
x := parse_expr(s) x := parse_expr(s, table)
println('source: $s') println('source: $s')
println('parsed: $x') println('parsed: $x')
println('===================') println('===================')
} }
} }
/*
fn test_cgen2() {
s := '2 + 3
5+7
//x := 100
'
table := &table.Table{}
prog := parse_file(s, table)
cgen.gen(prog)
println('done')
}
*/
fn test_cgen() { fn test_cgen() {
//if true { return }
s := [
'x := 10',
//'x := 10'
]
//expr := parse_expr('3 + 7 * 2') //expr := parse_expr('3 + 7 * 2')
//expr2 := parse_stmt('a := 3 + "f"') //expr2 := parse_stmt('a := 3 + "f"')
expr2 := parse_expr('2 + "helo"') mut e := []ast.Expr
program := ast.Program{ table := &table.Table{}
exprs: [ for ss in s {
expr2, //expr2 := parse_expr('x := 10')
//program := ast.Program{
e << parse_expr(ss, table)
//exprs: [
//expr2,
//parse_expr('2 * 2'), //parse_expr('2 * 2'),
] //]
} }
program := ast.Program{exprs:e}
cgen.gen(program) cgen.gen(program)
//cgen.save() //cgen.save()
} }

View File

@ -0,0 +1,7 @@
module table
pub struct Table {
pub mut:
names []string
}

View File

@ -289,7 +289,7 @@ fn (t []Token) contains(val Token) bool {
pub fn (t Token) str() string { pub fn (t Token) str() string {
lit := 't.lit' lit := 't.lit'
if t == .number { if t == .number {
return lit return 'number'
} }
if t == .chartoken { if t == .chartoken {
return '`lit`' return '`lit`'