v: initial impl of new type sys w/ pointer & placeholder support (#3323)

pull/3326/head
joe-conigliaro 2020-01-05 03:57:25 +11:00 committed by Alexander Medvednikov
parent 778a1cc34a
commit 2061394ad7
9 changed files with 667 additions and 173 deletions

View File

@ -17,7 +17,7 @@ ForStmt | StructDecl
pub struct ExprStmt { pub struct ExprStmt {
pub: pub:
expr Expr expr Expr
typ types.Type ti types.TypeIdent
} }
pub struct IntegerLiteral { pub struct IntegerLiteral {
@ -59,7 +59,7 @@ pub:
pub struct Field { pub struct Field {
pub: pub:
name string name string
typ types.Type ti types.TypeIdent
} }
pub struct StructDecl { pub struct StructDecl {
@ -71,7 +71,8 @@ pub:
pub struct StructInit { pub struct StructInit {
pub: pub:
typ types.Type ti types.TypeIdent
// typ types.Type
fields []string fields []string
exprs []Expr exprs []Expr
} }
@ -86,7 +87,8 @@ pub:
pub struct Arg { pub struct Arg {
pub: pub:
typ types.Type ti types.TypeIdent
// typ types.Type
name string name string
} }
@ -94,7 +96,8 @@ pub struct FnDecl {
pub: pub:
name string name string
stmts []Stmt stmts []Stmt
typ types.Type ti types.TypeIdent
// typ types.Type
args []Arg args []Arg
is_pub bool is_pub bool
receiver Field receiver Field
@ -133,7 +136,8 @@ pub struct VarDecl {
pub: pub:
name string name string
expr Expr expr Expr
typ types.Type ti types.TypeIdent
// typ types.Type
} }
pub struct File { pub struct File {
@ -174,7 +178,8 @@ pub:
cond Expr cond Expr
stmts []Stmt stmts []Stmt
else_stmts []Stmt else_stmts []Stmt
typ types.Type ti types.TypeIdent
// typ types.Type
left Expr // `a` in `a := if ...` left Expr // `a` in `a := if ...`
} }
@ -200,7 +205,8 @@ pub:
pub struct ArrayInit { pub struct ArrayInit {
pub: pub:
exprs []Expr exprs []Expr
typ types.Type ti types.TypeIdent
// typ types.Type
} }
// string representaiton of expr // string representaiton of expr

View File

@ -53,12 +53,12 @@ fn (g mut Gen) stmt(node ast.Stmt) {
g.write('int ${it.name}(') g.write('int ${it.name}(')
} }
else { else {
g.write('$it.typ.name ${it.name}(') g.write('$it.ti.type_name ${it.name}(')
g.definitions.write('$it.typ.name ${it.name}(') g.definitions.write('$it.ti.type_name ${it.name}(')
} }
for arg in it.args { for arg in it.args {
g.write(arg.typ.name + ' ' + arg.name) g.write(arg.ti.type_name + ' ' + arg.name)
g.definitions.write(arg.typ.name + ' ' + arg.name) g.definitions.write(arg.ti.type_name + ' ' + arg.name)
} }
g.writeln(') { ') g.writeln(') { ')
if !is_main { if !is_main {
@ -78,7 +78,7 @@ fn (g mut Gen) stmt(node ast.Stmt) {
g.writeln(';') g.writeln(';')
} }
ast.VarDecl { ast.VarDecl {
g.write('$it.typ.name $it.name = ') g.write('$it.ti.type_name $it.name = ')
g.expr(it.expr) g.expr(it.expr)
g.writeln(';') g.writeln(';')
} }
@ -98,7 +98,7 @@ fn (g mut Gen) stmt(node ast.Stmt) {
ast.StructDecl { ast.StructDecl {
g.writeln('typedef struct {') g.writeln('typedef struct {')
for field in it.fields { for field in it.fields {
g.writeln('\t$field.typ.name $field.name;') g.writeln('\t$field.ti.type_name $field.name;')
} }
g.writeln('} $it.name;') g.writeln('} $it.name;')
} }
@ -154,7 +154,7 @@ fn (g mut Gen) expr(node ast.Expr) {
} }
// `user := User{name: 'Bob'}` // `user := User{name: 'Bob'}`
ast.StructInit { ast.StructInit {
g.writeln('($it.typ.name){') g.writeln('($it.ti.type_name){')
for i, field in it.fields { for i, field in it.fields {
g.write('\t.$field = ') g.write('\t.$field = ')
g.expr(it.exprs[i]) g.expr(it.exprs[i])
@ -173,7 +173,7 @@ fn (g mut Gen) expr(node ast.Expr) {
g.write(')') g.write(')')
} }
ast.ArrayInit { ast.ArrayInit {
g.writeln('new_array_from_c_array($it.exprs.len, $it.exprs.len, sizeof($it.typ.name), {\t') g.writeln('new_array_from_c_array($it.exprs.len, $it.exprs.len, sizeof($it.ti.type_name), {\t')
for expr in it.exprs { for expr in it.exprs {
g.expr(expr) g.expr(expr)
g.write(', ') g.write(', ')
@ -200,7 +200,7 @@ fn (g mut Gen) expr(node ast.Expr) {
// If expression? Assign the value to a temp var. // If expression? Assign the value to a temp var.
// Previously ?: was used, but it's too unreliable. // Previously ?: was used, but it's too unreliable.
mut tmp := '' mut tmp := ''
if it.typ.idx != types.void_type.idx { if it.ti.type_kind != ._void {
tmp = g.table.new_tmp_var() tmp = g.table.new_tmp_var()
// g.writeln('$it.typ.name $tmp;') // g.writeln('$it.typ.name $tmp;')
} }
@ -209,7 +209,7 @@ fn (g mut Gen) expr(node ast.Expr) {
g.writeln(') {') g.writeln(') {')
for i, stmt in it.stmts { for i, stmt in it.stmts {
// Assign ret value // Assign ret value
if i == it.stmts.len - 1 && it.typ.idx != types.void_type.idx { if i == it.stmts.len - 1 && it.ti.type_kind != ._void {
// g.writeln('$tmp =') // g.writeln('$tmp =')
println(1) println(1)
} }

View File

@ -40,9 +40,9 @@ fn (g mut JsGen) stmt(node ast.Stmt) {
g.writeln(';') g.writeln(';')
} }
ast.FnDecl { ast.FnDecl {
g.write('/** @return { $it.typ.name } **/\nfunction ${it.name}(') g.write('/** @return { $it.ti.type_name } **/\nfunction ${it.name}(')
for arg in it.args { for arg in it.args {
g.write(' /** @type { arg.typ.name } **/ $arg.name') g.write(' /** @type { arg.ti.type_name } **/ $arg.name')
} }
g.writeln(') { ') g.writeln(') { ')
for stmt in it.stmts { for stmt in it.stmts {
@ -56,7 +56,7 @@ fn (g mut JsGen) stmt(node ast.Stmt) {
g.writeln(';') g.writeln(';')
} }
ast.VarDecl { ast.VarDecl {
g.write('var /* $it.typ.name */ $it.name = ') g.write('var /* $it.ti.type_name */ $it.name = ')
g.expr(it.expr) g.expr(it.expr)
g.writeln(';') g.writeln(';')
} }
@ -72,7 +72,7 @@ fn (g mut JsGen) stmt(node ast.Stmt) {
ast.StructDecl { ast.StructDecl {
// g.writeln('typedef struct {') // g.writeln('typedef struct {')
// for field in it.fields { // for field in it.fields {
// g.writeln('\t$field.typ.name $field.name;') // g.writeln('\t$field.ti.type_name $field.name;')
// } // }
g.writeln('var $it.name = function() {};') g.writeln('var $it.name = function() {};')
} }
@ -115,7 +115,7 @@ fn (g mut JsGen) expr(node ast.Expr) {
} }
// `user := User{name: 'Bob'}` // `user := User{name: 'Bob'}`
ast.StructInit { ast.StructInit {
g.writeln('/*$it.typ.name*/{') g.writeln('/*$it.ti.type_name*/{')
for i, field in it.fields { for i, field in it.fields {
g.write('\t$field : ') g.write('\t$field : ')
g.expr(it.exprs[i]) g.expr(it.exprs[i])

View File

@ -337,7 +337,7 @@ fn (g mut Gen) stmt(node ast.Stmt) {
g.writeln(';') g.writeln(';')
} }
ast.VarDecl { ast.VarDecl {
g.write('$it.typ.name $it.name = ') g.write('$it.ti.type_name $it.name = ')
g.expr(it.expr) g.expr(it.expr)
g.writeln(';') g.writeln(';')
} }
@ -354,7 +354,7 @@ fn (g mut Gen) stmt(node ast.Stmt) {
ast.StructDecl { ast.StructDecl {
g.writeln('typedef struct {') g.writeln('typedef struct {')
for field in it.fields { for field in it.fields {
g.writeln('\t$field.typ.name $field.name;') g.writeln('\t$field.ti.type_name $field.name;')
} }
g.writeln('} $it.name;') g.writeln('} $it.name;')
} }
@ -394,13 +394,13 @@ fn (g mut Gen) expr(node ast.Expr) {
g.expr(it.left) g.expr(it.left)
g.write(' $it.op.str() ') g.write(' $it.op.str() ')
g.expr(it.right) g.expr(it.right)
// if typ.name != typ2.name { // if ti.type_name != typ2.name {
// verror('bad types $typ.name $typ2.name') // verror('bad types $ti.type_name $typ2.name')
// } // }
} }
// `user := User{name: 'Bob'}` // `user := User{name: 'Bob'}`
ast.StructInit { ast.StructInit {
g.writeln('($it.typ.name){') g.writeln('($it.ti.type_name){')
for i, field in it.fields { for i, field in it.fields {
g.write('\t.$field = ') g.write('\t.$field = ')
g.expr(it.exprs[i]) g.expr(it.exprs[i])
@ -426,7 +426,7 @@ fn (g mut Gen) expr(node ast.Expr) {
} }
ast.ArrayInit { ast.ArrayInit {
g.writeln('new_array_from_c_array($it.exprs.len, $it.exprs.len, sizeof($it.typ.name), {\t') g.writeln('new_array_from_c_array($it.exprs.len, $it.exprs.len, sizeof($it.ti.type_name), {\t')
for expr in it.exprs { for expr in it.exprs {
g.expr(expr) g.expr(expr)
g.write(', ') g.write(', ')

View File

@ -13,20 +13,20 @@ import (
os os
) )
pub fn (p mut Parser) call_expr() (ast.CallExpr,types.Type) { pub fn (p mut Parser) call_expr() (ast.CallExpr,types.TypeIdent) {
// println('got fn call') // println('got fn call')
tok := p.tok tok := p.tok
fn_name := p.check_name() fn_name := p.check_name()
p.check(.lpar) p.check(.lpar)
mut is_unknown := false mut is_unknown := false
mut args := []ast.Expr mut args := []ast.Expr
mut return_type := types.void_type mut return_ti := types.new_base_ti(._void, 0)
if f := p.table.find_fn(fn_name) { if f := p.table.find_fn(fn_name) {
return_type = f.return_type return_ti = f.return_ti
for i, arg in f.args { for i, arg in f.args {
e,typ := p.expr(0) e,ti := p.expr(0)
if !types.check(arg.typ, typ) { if !types.check(arg.ti, ti) {
p.error('cannot use type `$typ.name` as type `$arg.typ.name` in argument to `$fn_name`') p.error('cannot use type `$ti.type_name` as type `$arg.ti.type_name` in argument to `$fn_name`')
} }
args << e args << e
if i < f.args.len - 1 { if i < f.args.len - 1 {
@ -59,7 +59,7 @@ pub fn (p mut Parser) call_expr() (ast.CallExpr,types.Type) {
if is_unknown { if is_unknown {
p.table.unknown_calls << node p.table.unknown_calls << node
} }
return node,return_type return node,return_ti
} }
fn (p mut Parser) fn_decl() ast.FnDecl { fn (p mut Parser) fn_decl() ast.FnDecl {
@ -71,17 +71,17 @@ fn (p mut Parser) fn_decl() ast.FnDecl {
p.check(.key_fn) p.check(.key_fn)
// Receiver? // Receiver?
mut rec_name := '' mut rec_name := ''
mut rec_type := types.void_type mut rec_ti := types.new_base_ti(._void, 0)
if p.tok.kind == .lpar { if p.tok.kind == .lpar {
p.next() p.next()
rec_name = p.check_name() rec_name = p.check_name()
if p.tok.kind == .key_mut { if p.tok.kind == .key_mut {
p.next() p.next()
} }
rec_type = p.parse_type() rec_ti = p.parse_ti()
p.table.register_var(table.Var{ p.table.register_var(table.Var{
name: rec_name name: rec_name
typ: rec_type ti: rec_ti
}) })
p.check(.rpar) p.check(.rpar)
} }
@ -98,16 +98,16 @@ fn (p mut Parser) fn_decl() ast.FnDecl {
p.check(.comma) p.check(.comma)
arg_names << p.check_name() arg_names << p.check_name()
} }
typ := p.parse_type() ti := p.parse_ti()
for arg_name in arg_names { for arg_name in arg_names {
arg := table.Var{ arg := table.Var{
name: arg_name name: arg_name
typ: typ ti: ti
} }
args << arg args << arg
p.table.register_var(arg) p.table.register_var(arg)
ast_args << ast.Arg{ ast_args << ast.Arg{
typ: typ ti: ti
name: arg_name name: arg_name
} }
} }
@ -117,26 +117,26 @@ fn (p mut Parser) fn_decl() ast.FnDecl {
} }
p.check(.rpar) p.check(.rpar)
// Return type // Return type
mut typ := types.void_type mut ti := types.new_base_ti(._void, 0)
if p.tok.kind == .name { if p.tok.kind in [.amp, .name] {
typ = p.parse_type() ti = p.parse_ti()
p.return_type = typ p.return_ti = ti
} }
p.table.register_fn(table.Fn{ p.table.register_fn(table.Fn{
name: name name: name
args: args args: args
return_type: typ return_ti: ti
}) })
stmts := p.parse_block() stmts := p.parse_block()
return ast.FnDecl{ return ast.FnDecl{
name: name name: name
stmts: stmts stmts: stmts
typ: typ ti: ti
args: ast_args args: ast_args
is_pub: is_pub is_pub: is_pub
receiver: ast.Field{ receiver: ast.Field{
name: rec_name name: rec_name
typ: rec_type ti: rec_ti
} }
} }
} }

View File

@ -21,7 +21,7 @@ mut:
peek_tok token.Token peek_tok token.Token
// vars []string // vars []string
table &table.Table table &table.Table
return_type types.Type return_ti types.TypeIdent
is_c bool is_c bool
} }
@ -35,6 +35,126 @@ pub fn parse_stmt(text string, table &table.Table) ast.Stmt {
return p.stmt() return p.stmt()
} }
pub fn (p mut Parser) parse_ti() types.TypeIdent {
defer {
p.next()
}
mut nr_muls := 0
if p.tok.kind == .amp {
p.check(.amp)
nr_muls = 1
}
name := p.tok.lit
if nr_muls > 0 {
println('## POINTER: $name')
}
match name {
'voidptr' {
return types.new_base_ti(._voidptr, nr_muls)
}
'byteptr' {
return types.new_base_ti(._byteptr, nr_muls)
}
'charptr' {
return types.new_base_ti(._charptr, nr_muls)
}
'164' {
return types.new_base_ti(._i16, nr_muls)
}
'int' {
return types.new_base_ti(._int, nr_muls)
}
'i64' {
return types.new_base_ti(._i64, nr_muls)
}
'byte' {
return types.new_base_ti(._byte, nr_muls)
}
'u16' {
return types.new_base_ti(._u16, nr_muls)
}
'u32' {
return types.new_base_ti(._u32, nr_muls)
}
'u64' {
return types.new_base_ti(._u64, nr_muls)
}
'f32' {
return types.new_base_ti(._f32, nr_muls)
}
'f64' {
return types.new_base_ti(._f64, nr_muls)
}
'string' {
return types.new_base_ti(._string, nr_muls)
}
'char' {
return types.new_base_ti(._char, nr_muls)
}
'bool' {
return types.new_base_ti(._bool, nr_muls)
}
else {
// array
if p.tok.kind == .lsbr {
p.check(.lsbr)
// fixed array
if p.tok.kind == .number {
fixed_size := p.tok.lit.int()
p.check(.rsbr)
elem_ti := p.parse_ti()
array_fixed_type := types.ArrayFixed{
name: 'array_fixed_$elem_ti.type_name'
size: fixed_size
elem_type_idx: elem_ti.type_idx
}
idx := p.table.find_or_register_array_fixed(array_fixed_type)
return types.new_ti(._array_fixed, array_fixed_type.name, idx, nr_muls)
}
p.check(.rsbr)
// array
elem_ti := p.parse_ti()
array_type := types.Array{
name: 'array_$elem_ti.type_name'
elem_type_idx: elem_ti.type_idx
}
idx := p.table.find_or_register_array(array_type)
return types.new_ti(._array, array_type.name, idx, nr_muls)
}
// map
else if name == 'map' {
p.next()
p.check(.lsbr)
key_ti := p.parse_ti()
p.check(.rsbr)
value_ti := p.parse_ti()
map_type := types.Map{
name: 'map_${key_ti.type_name}_${value_ti.type_name}'
key_type_idx: key_ti.type_idx,
value_type_idx: value_ti.type_idx
}
idx := p.table.find_or_register_map(map_type)
return types.new_ti(._map, map_type.name, idx, nr_muls)
} else {
// struct / enum
mut idx := p.table.find_type_idx(name)
// add placeholder
if idx == 0 {
idx = p.table.add_placeholder_type(name)
}
return types.new_ti(._placeholder, name, idx, nr_muls)
}
// typ := p.table.types[p.tok.lit]
// if isnil(typ.name.str) || typ.name == '' {
// p.error('undefined type `$p.tok.lit`')
// }
// println('RET Typ $typ.name')
// typ
}
}
}
pub fn parse_file(path string, table &table.Table) ast.File { pub fn parse_file(path string, table &table.Table) ast.File {
println('parse file "$path"') println('parse file "$path"')
text := os.read_file(path) or { text := os.read_file(path) or {
@ -74,16 +194,16 @@ pub fn parse_files(paths []string, table &table.Table) []ast.File {
} }
// former get_type() // former get_type()
pub fn (p mut Parser) parse_type() types.Type { // pub fn (p mut Parser) parse_ti() types.Type {
typ := p.table.find_type(p.tok.lit) or { // typ := p.table.find_type(p.tok.lit) or {
// typ := p.table.types[p.tok.lit] // // typ := p.table.types[p.tok.lit]
// if isnil(typ.name.str) || typ.name == '' { // // if isnil(typ.name.str) || typ.name == '' {
p.error('undefined type `$p.tok.lit`') // p.error('undefined type `$p.tok.lit`')
exit(0) // exit(0)
} // }
p.next() // p.next()
return typ // return typ
} // }
pub fn (p mut Parser) read_first_token() { pub fn (p mut Parser) read_first_token() {
// need to call next() twice to get peek token and current token // need to call next() twice to get peek token and current token
@ -184,10 +304,10 @@ pub fn (p mut Parser) stmt() ast.Stmt {
return p.for_statement() return p.for_statement()
} }
else { else {
expr,typ := p.expr(0) expr,ti := p.expr(0)
return ast.ExprStmt{ return ast.ExprStmt{
expr: expr expr: expr
typ: typ ti: ti
} }
} }
} }
@ -233,11 +353,12 @@ pub fn (p &Parser) warn(s string) {
} }
// Implementation of Pratt Precedence // Implementation of Pratt Precedence
pub fn (p mut Parser) expr(rbp int) (ast.Expr,types.Type) { pub fn (p mut Parser) expr(rbp int) (ast.Expr,types.TypeIdent) {
// println('expr at ' + p.tok.str()) // println('expr at ' + p.tok.str())
// null denotation (prefix) // null denotation (prefix)
mut node := ast.Expr{} mut node := ast.Expr{}
mut typ := types.void_type // mut typ := types.void_type
mut ti := types.new_base_ti(._void, 0)
match p.tok.kind { match p.tok.kind {
.name { .name {
/* /*
@ -254,13 +375,13 @@ pub fn (p mut Parser) expr(rbp int) (ast.Expr,types.Type) {
} }
// fn call // fn call
if p.peek_tok.kind == .lpar { if p.peek_tok.kind == .lpar {
x,typ2 := p.call_expr() // TODO `node,typ :=` should work x,ti2 := p.call_expr() // TODO `node,typ :=` should work
node = x node = x
typ = typ2 ti = ti2
} }
// struct init // struct init
else if p.peek_tok.kind == .lcbr { else if p.peek_tok.kind == .lcbr {
typ = p.parse_type() ti = p.parse_ti()
// println('sturct init typ=$typ.name') // println('sturct init typ=$typ.name')
p.check(.lcbr) p.check(.lcbr)
mut field_names := []string mut field_names := []string
@ -275,7 +396,7 @@ pub fn (p mut Parser) expr(rbp int) (ast.Expr,types.Type) {
exprs << expr exprs << expr
} }
node = ast.StructInit{ node = ast.StructInit{
typ: typ ti: ti
exprs: exprs exprs: exprs
fields: field_names fields: field_names
} }
@ -290,46 +411,46 @@ pub fn (p mut Parser) expr(rbp int) (ast.Expr,types.Type) {
p.error('unknown variable `$p.tok.lit`') p.error('unknown variable `$p.tok.lit`')
exit(0) exit(0)
} }
typ = var.typ ti = var.ti
// ///typ = types.int_type // ///typ = types.int_type
p.next() p.next()
} }
} }
.lsbr { .lsbr {
node,typ = p.array_init() node,ti = p.array_init()
} }
.key_true, .key_false { .key_true, .key_false {
node = ast.BoolLiteral{ node = ast.BoolLiteral{
val: p.tok.kind == .key_true val: p.tok.kind == .key_true
} }
typ = types.bool_type ti = types.new_base_ti(._bool, 0)
p.next() p.next()
} }
.str { .str {
node,typ = p.parse_string_literal() node,ti = p.parse_string_literal()
} }
.number { .number {
node,typ = p.parse_number_literal() node,ti = p.parse_number_literal()
} }
.key_if { .key_if {
node,typ = p.if_expr() node,ti = p.if_expr()
} }
.lpar { .lpar {
p.check(.lpar) p.check(.lpar)
p.next() p.next()
node,typ = p.expr(token.lowest_prec) node,ti = p.expr(token.lowest_prec)
p.check(.rpar) p.check(.rpar)
} }
else { else {
if p.tok.is_unary() { if p.tok.is_unary() {
pt := p.tok pt := p.tok
p.next() p.next()
expr,t2 := p.expr(token.lowest_prec) expr,ti2 := p.expr(token.lowest_prec)
node = ast.UnaryExpr{ node = ast.UnaryExpr{
left: expr left: expr
op: pt.kind op: pt.kind
} }
typ = t2 ti = ti2
} }
else { else {
p.error('expr(): unknown token ' + p.tok.str() + ' kind=$p.tok.kind') p.error('expr(): unknown token ' + p.tok.str() + ' kind=$p.tok.kind')
@ -340,30 +461,36 @@ pub fn (p mut Parser) expr(rbp int) (ast.Expr,types.Type) {
for rbp < p.tok.precedence() { for rbp < p.tok.precedence() {
prev_tok := p.tok prev_tok := p.tok
p.next() p.next()
mut t2 := types.Type{} // mut t2 := types.Type{}
mut ti2 := types.new_base_ti(._void, 0)
// left denotation (infix / postfix) // left denotation (infix / postfix)
if prev_tok.is_right_assoc() && !p.tok.kind in [.plus, .minus] && // think of better way to handle this if prev_tok.is_right_assoc() && !p.tok.kind in [.plus, .minus] && // think of better way to handle this
!p.peek_tok.kind in [.number, .name] { !p.peek_tok.kind in [.number, .name] {
// supposed to be only unary, additive handled in left asssoc // supposed to be only unary, additive handled in left asssoc
mut expr := ast.Expr{} mut expr := ast.Expr{}
expr,t2 = p.expr(prev_tok.precedence() - 1) expr,ti2 = p.expr(prev_tok.precedence() - 1)
node = ast.BinaryExpr{ node = ast.BinaryExpr{
left: node left: node
op: prev_tok.kind op: prev_tok.kind
right: expr right: expr
} }
// println(t2.name + 'OOO') // println(t2.name + 'OOO')
if !types.check(&typ, &t2) { if !types.check(&ti, &ti2) {
println('tok: $prev_tok.str()') println('tok: $prev_tok.str()')
p.error('cannot convert `$t2.name` to `$typ.name`') p.error('cannot convert `$ti2.type_name` to `$ti.type_name`')
} }
} }
else if prev_tok.is_left_assoc() { else if prev_tok.is_left_assoc() {
// postfix `.` // postfix `.`
if prev_tok.kind == .dot { if prev_tok.kind == .dot {
p.warn('dot prev_tok = $prev_tok.str() typ=$typ.name') p.warn('dot prev_tok = $prev_tok.str() typ=$ti.type_name')
// p.next() // p.next()
field := p.check_name() field := p.check_name()
if !ti.type_kind in [._placeholder, ._struct] {
println('kind: $ti.str()')
p.error('cannot access field, `$ti.type_name` is not a struct')
}
typ := p.table.types[ti.type_idx] as types.Struct
mut ok := false mut ok := false
for f in typ.fields { for f in typ.fields {
if f.name == field { if f.name == field {
@ -388,14 +515,15 @@ pub fn (p mut Parser) expr(rbp int) (ast.Expr,types.Type) {
} }
else { else {
mut expr := ast.Expr{} mut expr := ast.Expr{}
expr,t2 = p.expr(prev_tok.precedence() - 1) expr,ti2 = p.expr(prev_tok.precedence() - 1)
if prev_tok.is_relational() { if prev_tok.is_relational() {
typ = types.bool_type // typ = types.bool_type
ti = types.new_base_ti(._bool, 0)
} }
else { else {
typ = t2 ti = ti2
} }
// println(t2.name + '222') // println(ti2.type_name + '222')
node = ast.BinaryExpr{ node = ast.BinaryExpr{
left: node left: node
op: prev_tok.kind op: prev_tok.kind
@ -404,7 +532,7 @@ pub fn (p mut Parser) expr(rbp int) (ast.Expr,types.Type) {
} }
} }
} }
return node,typ return node,ti
} }
[inline] [inline]
@ -432,8 +560,9 @@ fn (p mut Parser) for_statement() ast.ForStmt {
} }
} }
// `for cond {` // `for cond {`
cond,typ := p.expr(0) cond,ti := p.expr(0)
if !types.check(types.bool_type, typ) { // if !types.check(types.bool_type, ti) {
if ti.type_kind != ._bool {
p.error('non-bool used as for condition') p.error('non-bool used as for condition')
} }
stmts := p.parse_block() stmts := p.parse_block()
@ -443,11 +572,12 @@ fn (p mut Parser) for_statement() ast.ForStmt {
} }
} }
fn (p mut Parser) if_expr() (ast.Expr,types.Type) { fn (p mut Parser) if_expr() (ast.Expr,types.TypeIdent) {
mut node := ast.Expr{} mut node := ast.Expr{}
p.check(.key_if) p.check(.key_if)
cond,cond_type := p.expr(0) cond,cond_type := p.expr(0)
if !types.check(types.bool_type, cond_type) { // if !types.check(types.bool_type, cond_type) {
if cond_type.type_kind != ._bool {
p.error('non-bool used as if condition') p.error('non-bool used as if condition')
} }
stmts := p.parse_block() stmts := p.parse_block()
@ -457,13 +587,14 @@ fn (p mut Parser) if_expr() (ast.Expr,types.Type) {
p.check(.key_else) p.check(.key_else)
else_stmts = p.parse_block() else_stmts = p.parse_block()
} }
mut typ := types.void_type // mut typ := types.void_type
mut ti := types.new_base_ti(._void, 0)
// mut left := ast.Expr{} // mut left := ast.Expr{}
// If the last statement is an expression, return its type // If the last statement is an expression, return its type
match stmts[stmts.len - 1] { match stmts[stmts.len - 1] {
ast.ExprStmt { ast.ExprStmt {
p.warn('if expr ret $it.typ.name') p.warn('if expr ret $it.ti.type_name')
typ = it.typ ti = it.ti
// return node,it.typ // return node,it.typ
// left = // left =
} }
@ -473,35 +604,37 @@ fn (p mut Parser) if_expr() (ast.Expr,types.Type) {
cond: cond cond: cond
stmts: stmts stmts: stmts
else_stmts: else_stmts else_stmts: else_stmts
typ: typ ti: ti
// left: left // left: left
} }
return node,typ return node,ti
} }
fn (p mut Parser) parse_string_literal() (ast.Expr,types.Type) { fn (p mut Parser) parse_string_literal() (ast.Expr,types.TypeIdent) {
mut node := ast.Expr{} mut node := ast.Expr{}
node = ast.StringLiteral{ node = ast.StringLiteral{
val: p.tok.lit val: p.tok.lit
} }
p.next() p.next()
return node,types.string_type // return node,types.string_type
return node, types.new_base_ti(._string, 0)
} }
fn (p mut Parser) array_init() (ast.Expr,types.Type) { fn (p mut Parser) array_init() (ast.Expr,types.TypeIdent) {
p.check(.lsbr) p.check(.lsbr)
mut val_type := types.void_type // mut val_type := types.void_type
mut val_ti := types.new_base_ti(._void, 0)
mut exprs := []ast.Expr mut exprs := []ast.Expr
mut i := 0 mut i := 0
for p.tok.kind != .rsbr { for p.tok.kind != .rsbr {
expr,typ := p.expr(0) expr,ti := p.expr(0)
// The first element's type // The first element's type
if i == 0 { if i == 0 {
val_type = typ val_ti = ti
} }
else if !types.check(val_type, typ) { else if !types.check(val_ti, ti) {
p.error('expected array element with type `$val_type.name`') p.error('expected array element with type `$val_ti.type_name`')
} }
exprs << expr exprs << expr
i++ i++
@ -511,32 +644,32 @@ fn (p mut Parser) array_init() (ast.Expr,types.Type) {
} }
mut node := ast.Expr{} mut node := ast.Expr{}
node = ast.ArrayInit{ node = ast.ArrayInit{
typ: val_type ti: val_ti
exprs: exprs exprs: exprs
} }
p.check(.rsbr) p.check(.rsbr)
return node,val_type return node,val_ti
} }
fn (p mut Parser) parse_number_literal() (ast.Expr,types.Type) { fn (p mut Parser) parse_number_literal() (ast.Expr,types.TypeIdent) {
lit := p.tok.lit lit := p.tok.lit
mut node := ast.Expr{} mut node := ast.Expr{}
mut typ := types.int_type mut ti := types.new_base_ti(._int, 0)
if lit.contains('.') { if lit.contains('.') {
node = ast.FloatLiteral{ node = ast.FloatLiteral{
// val: lit.f64() // val: lit.f64()
val: lit val: lit
} }
typ = types.f64_type ti = types.new_base_ti(._f64, 0)
} }
else { else {
node = ast.IntegerLiteral{ node = ast.IntegerLiteral{
val: lit.int() val: lit.int()
} }
typ = types.int_type // ti = types.new_base_ti(._int, 0)
} }
p.next() p.next()
return node,typ return node,ti
} }
fn (p mut Parser) module_decl() ast.Module { fn (p mut Parser) module_decl() ast.Module {
@ -569,18 +702,22 @@ fn (p mut Parser) struct_decl() ast.StructDecl {
p.check(.colon) p.check(.colon)
} }
field_name := p.check_name() field_name := p.check_name()
typ := p.parse_type() ti := p.parse_ti()
ast_fields << ast.Field{ ast_fields << ast.Field{
name: field_name name: field_name
typ: typ ti: ti
} }
fields << types.Field{ fields << types.Field{
name: field_name name: field_name
type_idx: typ.idx type_idx: ti.type_idx
} }
} }
p.check(.rcbr) p.check(.rcbr)
p.table.register_type(types.Type{ if name in p.table.type_idxs {
println('placeholder exists: $name')
}
println('about to register: $name')
p.table.register_struct(types.Struct{
name: name name: name
fields: fields fields: fields
}) })
@ -594,8 +731,8 @@ fn (p mut Parser) struct_decl() ast.StructDecl {
fn (p mut Parser) return_stmt() ast.Return { fn (p mut Parser) return_stmt() ast.Return {
p.next() p.next()
expr,t := p.expr(0) expr,t := p.expr(0)
if !types.check(p.return_type, t) { if !types.check(p.return_ti, t) {
p.error('cannot use `$t.name` as type `$p.return_type.name` in return argument') p.error('cannot use `$t.type_name` as type `$p.return_ti.type_name` in return argument')
} }
return ast.Return{ return ast.Return{
expr: expr expr: expr
@ -621,7 +758,7 @@ fn (p mut Parser) var_decl() ast.VarDecl {
} }
p.table.register_var(table.Var{ p.table.register_var(table.Var{
name: name name: name
typ: t ti: t
is_mut: is_mut is_mut: is_mut
}) })
// println(p.table.names) // println(p.table.names)
@ -630,7 +767,7 @@ fn (p mut Parser) var_decl() ast.VarDecl {
name: name name: name
expr: expr // p.expr(token.lowest_prec) expr: expr // p.expr(token.lowest_prec)
typ: t ti: t
} }
} }

View File

@ -8,7 +8,9 @@ import (
pub struct Table { pub struct Table {
// struct_fields map[string][]string // struct_fields map[string][]string
pub mut: pub mut:
types map[string]types.Type // types map[string]types.Type
types []types.Type
type_idxs map[string]int
local_vars []Var local_vars []Var
// fns Hashmap // fns Hashmap
fns map[string]Fn fns map[string]Fn
@ -20,7 +22,7 @@ pub mut:
pub struct Var { pub struct Var {
pub: pub:
name string name string
typ types.Type ti types.TypeIdent
is_mut bool is_mut bool
} }
@ -28,17 +30,23 @@ pub struct Fn {
pub: pub:
name string name string
args []Var args []Var
return_type types.Type return_ti types.TypeIdent
} }
pub fn new_table() &Table { pub fn new_table() &Table {
// mut t := &Table{}
// t.register_type(types.void_type)
// t.register_type(types.int_type)
// t.register_type(types.string_type)
// t.register_type(types.f64_type)
// t.register_type(types.bool_type)
// t.register_type(types.voidptr_type)
mut t := &Table{} mut t := &Table{}
t.register_type(types.void_type) // add dummy type at 0 so nothing can go there
t.register_type(types.int_type) // save index check, 0 will mean not found
t.register_type(types.string_type) t.types << types.Type{}
t.register_type(types.f64_type) t.type_idxs['dymmy_type_at_idx_0'] = 0
t.register_type(types.bool_type)
t.register_type(types.voidptr_type)
return t return t
} }
@ -109,19 +117,106 @@ pub fn (t mut Table) register_fn(new_fn Fn) {
t.fns[new_fn.name] = new_fn t.fns[new_fn.name] = new_fn
} }
pub fn (t mut Table) register_type(typ types.Type) { pub fn (t mut Table) register_struct(typ types.Struct) int {
t.types[typ.name] = typ mut t2 := types.Type{}
// existing
existing_idx := t.type_idxs[typ.name]
if existing_idx > 0 {
ex_type := t.types[existing_idx]
match ex_type {
types.Placeholder {
// override placeholder
println('placeholder exists: $it.name overidding')
t2 = {typ| idx: existing_idx}
t.types[existing_idx] = t2
return existing_idx
}
else {}
}
}
// register
println('registering: $typ.name')
idx := t.types.len
t.type_idxs[typ.name] = idx
t2 = {typ| idx: idx}
t.types << t2
return idx
}
pub fn (t mut Table) find_or_register_map(typ types.Map) int {
// existing
existing_idx := t.type_idxs[typ.name]
if existing_idx > 0 {
return existing_idx
}
// register
idx := t.types.len
mut t2 := types.Type{}
t2 = {typ| idx: idx}
t.type_idxs[typ.name] = idx
t.types << t2
return idx
}
pub fn (t mut Table) find_or_register_array(typ types.Array) int {
// existing
existing_idx := t.type_idxs[typ.name]
if existing_idx > 0 {
return existing_idx
}
// register
idx := t.types.len
mut t2 := types.Type{}
t2 = {typ| idx: idx}
t.type_idxs[typ.name] = idx
t.types << t2
return idx
}
pub fn (t mut Table) find_or_register_array_fixed(typ types.ArrayFixed) int {
// existing
existing_idx := t.type_idxs[typ.name]
if existing_idx > 0 {
return existing_idx
}
// register
idx := t.types.len
mut t2 := types.Type{}
t2 = {typ| idx: idx}
t.type_idxs[typ.name] = idx
t.types << t2
return idx
}
[inline]
pub fn (t &Table) find_type_idx(name string) int {
return t.type_idxs[name]
}
pub fn (t mut Table) add_placeholder_type(name string) int {
idx := t.types.len
t.type_idxs[name] = t.types.len
mut pt := types.Type{}
pt = types.Placeholder{
idx: idx
name: name
}
println('added placeholder: $name - $idx ')
t.types << pt
return idx
} }
pub fn (t &Table) find_type(name string) ?types.Type { pub fn (t &Table) find_type(name string) ?types.Type {
typ := t.types[name] idx := t.type_idxs[name]
if isnil(typ.name.str) || typ.name == '' { if idx > 0 {
return none return t.types[idx]
} }
return typ return none
} }
pub fn (t mut Table) new_tmp_var() string { pub fn (t mut Table) new_tmp_var() string {
t.tmp_cnt++ t.tmp_cnt++
return 'tmp$t.tmp_cnt' return 'tmp$t.tmp_cnt'
} }

View File

@ -4,16 +4,208 @@
module types module types
pub enum Kind { pub enum Kind {
struct_ _placeholder,
builtin _void,
enum_ _voidptr,
_charptr,
_byteptr,
_const,
_enum,
_struct,
_int,
_i8,
_i16,
_i64,
_byte,
_u16,
_u32,
_u64,
_f32,
_f64,
_string,
_char,
_bool,
_array,
_array_fixed,
_map,
_multi_return,
_variadic
} }
pub struct Type { pub struct TypeIdent {
pub:
type_idx int
type_kind Kind
type_name string
nr_muls int
}
[inline]
pub fn new_ti(type_kind Kind, type_name string, type_idx int, nr_muls int) TypeIdent {
return TypeIdent{
type_idx: type_idx
type_kind: type_kind
type_name: type_name
nr_muls: nr_muls
}
}
[inline]
pub fn new_base_ti(type_kind Kind, nr_muls int) TypeIdent {
return TypeIdent{
type_kind: type_kind
type_name: type_kind.str()
nr_muls: nr_muls
}
}
[inline]
pub fn (ti &TypeIdent) is_ptr() bool {
return ti.nr_muls > 0
}
[inline]
pub fn (ti &TypeIdent) is_int() bool {
return ti.type_kind in [._i8, ._i16, ._int, ._i64, ._byte, ._u16, ._u32, ._u64]
}
[inline]
pub fn (ti &TypeIdent) is_float() bool {
return ti.type_kind in [._f32, ._f64]
}
[inline]
pub fn (ti &TypeIdent) is_number() bool {
return ti.is_int() || ti.is_float()
}
pub fn (ti &TypeIdent) str() string {
return '$ti.type_kind.str() $ti.type_idx: $ti.type_name ($ti.nr_muls)'
}
pub fn check(got, expected &TypeIdent) bool {
if got.type_idx != expected.type_idx {
return false
}
return true
}
pub fn (t Kind) str() string {
t_str := match t {
._placeholder {
'placeholder'
}
._void {
'void'
}
._voidptr {
'voidptr'
}
._charptr {
'charptr'
}
._byteptr {
'byteptr'
}
._const {
'const'
}
._enum {
'enum'
}
._struct {
'struct'
}
._int {
'int'
}
._i8 {
'i8'
}
._i16 {
'i16'
}
._i64 {
'i64'
}
._byte {
'byte'
}
._u16 {
'u18'
}
._f32 {
'f32'
}
._f64 {
'f64'
}
._string {
'string'
}
._char {
'char'
}
._bool {
'bool'
}
._array {
'array'
}
._array_fixed {
'array_fixed'
}
._map {
'map'
}
._multi_return {
'multi_return'
}
._variadic {
'variadic'
}
else {
'unknown'
}
}
return t_str
}
pub type Type = Placeholder | Void | Voidptr | Charptr | Byteptr | Const | Enum | Struct |
Int | Float | String | Char | Byte | Bool | Array | ArrayFixed | Map | MultiReturn | Variadic
pub struct Placeholder {
pub: pub:
name string
idx int idx int
// kind Kind name string
kind Kind
}
pub struct Void {}
pub struct Voidptr {}
pub struct Charptr {}
pub struct Byteptr {}
pub struct Const {
pub:
idx int
name string
}
pub struct Enum {
pub:
idx int
name string
}
pub struct Struct {
pub:
idx int
name string
fields []Field fields []Field
} }
@ -23,36 +215,95 @@ pub:
type_idx int type_idx int
} }
pub const ( pub struct Int {
void_type = Type{ pub:
name: 'void' bit_size u32
idx: 0 is_unsigned bool
}
int_type = Type{
name: 'int'
idx: 1
}
string_type = Type{
name: 'string'
idx: 2
}
f64_type = Type{
name: 'f64'
idx: 3
}
bool_type = Type{
name: 'bool'
idx: 4
}
voidptr_type = Type{
name: 'voidptr'
idx: 5
}
)
pub fn check(got, expected &Type) bool {
if got.idx != expected.idx {
return false
}
return true
} }
pub struct Float {
bit_size u32
}
pub struct String {}
pub struct Char {}
pub struct Byte {}
pub struct Bool {}
pub struct Array {
pub:
idx int
name string
elem_type_kind Kind
elem_type_idx int
nr_dims int
}
pub struct ArrayFixed {
pub:
idx int
name string
elem_type_kind Kind
elem_type_idx int
size int
}
pub struct Map {
pub:
idx int
name string
key_type_kind Kind
key_type_idx int
value_type_kind Kind
value_type_idx int
}
pub struct MultiReturn {
pub:
elem_type_kinds []Kind
elem_type_idxs []int
}
pub struct Variadic {
pub:
elem_type_kind Kind
elem_type_idx int
}
pub fn (t Void) str() string { return 'void' }
pub fn (t Voidptr) str() string { return 'voidptr' }
pub fn (t Charptr) str() string { return 'charptr' }
pub fn (t Byteptr) str() string { return 'Byteptr' }
pub fn (t Const) str() string { return t.name }
pub fn (t Enum) str() string { return t.name }
pub fn (t Struct) str() string { return t.name }
pub fn (t Int) str() string { return if t.is_unsigned {'u$t.bit_size' } else { 'i$t.bit_size' } }
pub fn (t Float) str() string { return 'f$t.bit_size' }
pub fn (t String) str() string { return 'string' }
pub fn (t Char) str() string { return 'char' }
pub fn (t Byte) str() string { return 'byte' }
pub fn (t Array) str() string { return t.name }
pub fn (t ArrayFixed) str() string { return t.name }
pub fn (t Map) str() string { return t.name }
pub fn (t MultiReturn) str() string { return 'multi_return_$t.elem_type_kinds.str()' }
pub fn (t Variadic) str() string { return 'variadic_$t.elem_type_kind.str()' }
pub const (
void_type = Void{}
voidptr_type = Voidptr{}
charptr_type = Charptr{}
byteptr_type = Byteptr{}
int_type = Int{32, false}
i64_type = Int{64, false}
byte_type = Int{8, true}
u32_type = Int{32, true}
u64_type = Int{64, true}
f32_type = Float{32}
f64_type = Float{64}
string_type = String{}
char_type = Char{}
bool_type = Bool{}
)

View File

@ -0,0 +1,5 @@
module types
fn test_types() {
}